// Copyright (c) 2017 PSForever
package net.psforever.packet

import scodec.{Attempt, Codec, DecodeResult, Err}
import scodec.bits.BitVector
import scodec.codecs._

import scala.annotation.switch

/**
  * The master list of Game packet opcodes that have been discovered in the PlanetSide client.
  *
  * UnknownMessage* means that there, to the best of our knowledge, was no opcode of this value.
  * This was double checked by extracting out the master case statement in PlanetsideComm::OnReceive
  * and by parsing NetMessage RTTI.
  */
object GamePacketOpcode extends Enumeration {
  type Type = Value
  val
  // OPCODES 0x00-0f
  Unknown0,                     // PPT_NULL in beta client
  LoginMessage,                 //
  LoginRespMessage,             //
  ConnectToWorldRequestMessage, // found by searching for 83 F8 03 89 in IDA
  ConnectToWorldMessage,        //
  VNLWorldStatusMessage,        //
  UnknownMessage6,              // PPT_TRANSFERTOWORLDREQUEST
  UnknownMessage7,              // PPT_TRANSFERTOWORLDRESPONSE
  // 0x08
  PlayerStateMessage, //
  HitMessage,         //
  HitHint,            //
  DamageMessage,      //
  DestroyMessage,     //
  ReloadMessage,      //
  MountVehicleMsg,    //
  DismountVehicleMsg, //
  // OPCODES 0x10-1f
  UseItemMessage,                //
  MoveItemMessage,               //
  ChatMsg,                       //
  CharacterNoRecordMessage,      //
  CharacterInfoMessage,          //
  UnknownMessage21,              // PPT_DISCONNECT
  BindPlayerMessage,             //
  ObjectCreateMessage_Duplicate, // PPT_OBJECTCREATE
  // 0x18
  ObjectCreateMessage,      // PPT_OBJECTCREATEDETAILED
  ObjectDeleteMessage,      //
  PingMsg,                  //
  VehicleStateMessage,      //
  FrameVehicleStateMessage, //
  GenericObjectStateMsg,    //
  ChildObjectStateMessage,  //
  ActionResultMessage,      //
  // OPCODES 0x20-2f
  UnknownMessage32,               // PPT_ACTIONBEGIN
  ActionProgressMessage,          //
  ActionCancelMessage,            //
  ActionCancelAcknowledgeMessage, //
  SetEmpireMessage,               //
  EmoteMsg,                       //
  UnuseItemMessage,               //
  ObjectDetachMessage,            //
  // 0x28
  CreateShortcutMessage,         //
  ChangeShortcutBankMessage,     //
  ObjectAttachMessage,           //
  UnknownMessage43,              // PPT_OBJECTEMPTY
  PlanetsideAttributeMessage,    //
  RequestDestroyMessage,         //
  UnknownMessage46,              // PPT_EQUIPITEM
  CharacterCreateRequestMessage, //
  // OPCODES 0x30-3f
  CharacterRequestMessage, //
  LoadMapMessage,          //
  SetCurrentAvatarMessage, //
  ObjectHeldMessage,       //
  WeaponFireMessage,       //
  AvatarJumpMessage,       //
  PickupItemMessage,       //
  DropItemMessage,         //
  // 0x38
  InventoryStateMessage,        //
  ChangeFireStateMessage_Start, //
  ChangeFireStateMessage_Stop,  //
  UnknownMessage59,             //
  GenericCollisionMsg,          //
  QuantityUpdateMessage,        //
  ArmorChangedMessage,          //
  ProjectileStateMessage,       //
  // OPCODES 0x40-4f
  MountVehicleCargoMsg,         //
  DismountVehicleCargoMsg,      //
  CargoMountPointStatusMessage, //
  BeginZoningMessage,           //
  ItemTransactionMessage,       //
  ItemTransactionResultMessage, //
  ChangeFireModeMessage,        //
  ChangeAmmoMessage,            //
  // 0x48
  TimeOfDayMessage,         //
  UnknownMessage73,         // PPT_PROJECTILE_EVENT_BLOCK
  SpawnRequestMessage,      //
  DeployRequestMessage,     //
  UnknownMessage76,         // PPT_BUILDINGSTATECHANGED
  RepairMessage,            //
  ServerVehicleOverrideMsg, //
  LashMessage,
  // OPCODES 0x50-5f
  TargetingInfoMessage,         //
  TriggerEffectMessage,         //
  WeaponDryFireMessage,         //
  DroppodLaunchRequestMessage,  //
  HackMessage,                  //
  DroppodLaunchResponseMessage, //
  GenericObjectActionMessage,   //
  AvatarVehicleTimerMessage,    //
  // 0x58
  AvatarImplantMessage,  //
  UnknownMessage89,      // PPT_SEARCHMESSAGE
  DelayedPathMountMsg,   //
  OrbitalShuttleTimeMsg, //
  AIDamage,              //
  DeployObjectMessage,   //
  FavoritesRequest,      //
  FavoritesResponse,     //
  // OPCODES 0x60-6f
  FavoritesMessage,            //
  ObjectDetectedMessage,       //
  SplashHitMessage,            //
  SetChatFilterMessage,        //
  AvatarSearchCriteriaMessage, //
  AvatarSearchResponse,        //
  WeaponJammedMessage,         //
  LinkDeadAwarenessMsg,        //
  // 0x68
  DroppodFreefallingMessage,   //
  AvatarFirstTimeEventMessage, //
  AggravatedDamageMessage,     //
  TriggerSoundMessage,         //
  LootItemMessage,             //
  VehicleSubStateMessage,      //
  SquadMembershipRequest,      //
  SquadMembershipResponse,     //
  // OPCODES 0x70-7f
  SquadMemberEvent,                  //
  PlatoonEvent,                      //
  FriendsRequest,                    //
  FriendsResponse,                   //
  TriggerEnvironmentalDamageMessage, //
  TrainingZoneMessage,               //
  DeployableObjectsInfoMessage,      //
  SquadState,
  // 0x78
  OxygenStateMessage,      //
  TradeMessage,            //
  UnknownMessage122,       //
  DamageFeedbackMessage,   //
  DismountBuildingMsg,     //
  UnknownMessage125,       // PPT_MOUNTBUILDING
  UnknownMessage126,       // PPT_INTENDEDDROPZONE
  AvatarStatisticsMessage, //
  // OPCODES 0x80-8f
  GenericObjectAction2Message, //
  DestroyDisplayMessage,       //
  TriggerBotAction,            //
  SquadWaypointRequest,        //
  SquadWaypointEvent,          //
  OffshoreVehicleMessage,      //
  ObjectDeployedMessage,       //
  ObjectDeployedCountMessage,  //
  // 0x88
  WeaponDelayFireMessage,   //
  BugReportMessage,         //
  PlayerStasisMessage,      //
  UnknownMessage139,        //
  OutfitMembershipRequest,  //
  OutfitMembershipResponse, //
  OutfitRequest,            //
  OutfitEvent,              //
  // OPCODES 0x90-9f
  OutfitMemberEvent,                //
  OutfitMemberUpdate,               //
  PlanetsideStringAttributeMessage, //
  DataChallengeMessage,             //
  DataChallengeMessageResp,         //
  WeatherMessage,                   //
  SimDataChallenge,                 //
  SimDataChallengeResp,             //
  // 0x98
  OutfitListEvent,         //
  EmpireIncentivesMessage, //
  InvalidTerrainMessage,   //
  SyncMessage,             //
  DebugDrawMessage,        //
  SoulMarkMessage,         //
  UplinkPositionEvent,     //
  HotSpotUpdateMessage,    //
  // OPCODES 0xa0-af
  BuildingInfoUpdateMessage, //
  FireHintMessage,           //
  UplinkRequest,             //
  UplinkResponse,            //
  WarpgateRequest,           //
  WarpgateResponse,          //
  DamageWithPositionMessage, //
  GenericActionMessage,      //
  // 0xa8
  ContinentalLockUpdateMessage, //
  AvatarGrenadeStateMessage,    //
  UnknownMessage170,            //
  UnknownMessage171,            //
  ReleaseAvatarRequestMessage,  //
  AvatarDeadStateMessage,       //
  CSAssistMessage,              //
  CSAssistCommentMessage,       //
  // OPCODES 0xb0-bf
  VoiceHostRequest,            //
  VoiceHostKill,               //
  VoiceHostInfo,               //
  BattleplanMessage,           //
  BattleExperienceMessage,     //
  TargetingImplantRequest,     //
  ZonePopulationUpdateMessage, //
  DisconnectMessage,           //
  // 0xb8
  ExperienceAddedMessage,       //
  OrbitalStrikeWaypointMessage, //
  KeepAliveMessage,             //
  MapObjectStateBlockMessage,   //
  SnoopMsg,                     //
  PlayerStateMessageUpstream,   //
  PlayerStateShiftMessage,      //
  ZipLineMessage,               //
  // OPCODES 0xc0-cf
  CaptureFlagUpdateMessage,                  //
  VanuModuleUpdateMessage,                   //
  FacilityBenefitShieldChargeRequestMessage, //
  ProximityTerminalUseMessage,               //
  QuantityDeltaUpdateMessage,                //
  ChainLashMessage,                          //
  ZoneInfoMessage,                           //
  LongRangeProjectileInfoMessage,            //
  // 0xc8
  WeaponLazeTargetPositionMessage, //
  ModuleLimitsMessage,             //
  OutfitBenefitMessage,            //
  EmpireChangeTimeMessage,         //
  ClockCalibrationMessage,         //
  DensityLevelUpdateMessage,       //
  ActOfGodMessage,                 //
  AvatarAwardMessage,              //
  // OPCODES 0xd0-df
  UnknownMessage208,                    //
  DisplayedAwardMessage,                //
  RespawnAMSInfoMessage,                //
  ComponentDamageMessage,               //
  GenericObjectActionAtPositionMessage, //
  PropertyOverrideMessage,              //
  WarpgateLinkOverrideMessage,          //
  EmpireBenefitsMessage,                //
  // 0xd8
  ForceEmpireMessage,               //
  BroadcastWarpgateUpdateMessage,   //
  UnknownMessage218,                //
  SquadMainTerminalMessage,         //
  SquadMainTerminalResponseMessage, //
  SquadOrderMessage,                //
  SquadOrderResponse,               //
  ZoneLockInfoMessage,              //
  // OPCODES 0xe0-ef
  SquadBindInfoMessage,               //
  AudioSequenceMessage,               //
  SquadFacilityBindInfoMessage,       //
  ZoneForcedCavernConnectionsMessage, //
  MissionActionMessage,               //
  MissionKillTriggerMessage,          //
  ReplicationStreamMessage,           //
  SquadDefinitionActionMessage,       //
  // 0xe8
  SquadDetailDefinitionUpdateMessage, //
  TacticsMessage,                     //
  RabbitUpdateMessage,                //
  SquadInvitationRequestMessage,      //
  CharacterKnowledgeMessage,          //
  GameScoreUpdateMessage,             //
  UnknownMessage238,                  //
  OrderTerminalBugMessage,            //
  // OPCODES 0xf0-f3
  QueueTimedHelpMessage, //
  MailMessage,           //
  GameVarUpdate,         //
  ClientCheatedMessage   // last known message type (243, 0xf3)
  = Value

  private def noDecoder(opcode: GamePacketOpcode.Type) =
    (bits: BitVector) => Attempt.failure(Err(s"Could not find a marshaller for game packet $opcode (${bits.toHex})"))

  /// Mapping of packet IDs to decoders. Notice that we are using the @switch annotation which ensures that the Scala
  /// compiler will be able to optimize this as a lookup table (switch statement). Microbenchmarks show a nearly 400x
  /// speedup when using a switch (given the worst case of not finding a decoder)
  def getPacketDecoder(opcode: GamePacketOpcode.Type): BitVector => Attempt[DecodeResult[PlanetSideGamePacket]] =
    (opcode.id: @switch) match {
      // OPCODES 0x00-0f
      case 0x00 => noDecoder(Unknown0)
      case 0x01 => game.LoginMessage.decode
      case 0x02 => game.LoginRespMessage.decode
      case 0x03 => game.ConnectToWorldRequestMessage.decode
      case 0x04 => game.ConnectToWorldMessage.decode
      case 0x05 => game.VNLWorldStatusMessage.decode
      case 0x06 => noDecoder(UnknownMessage6)
      case 0x07 => noDecoder(UnknownMessage7)
      // 0x08
      case 0x08 => game.PlayerStateMessage.decode
      case 0x09 => game.HitMessage.decode
      case 0x0a => game.HitHint.decode
      case 0x0b => game.DamageMessage.decode
      case 0x0c => game.DestroyMessage.decode
      case 0x0d => game.ReloadMessage.decode
      case 0x0e => game.MountVehicleMsg.decode
      case 0x0f => game.DismountVehicleMsg.decode

      // OPCODES 0x10-1f
      case 0x10 => game.UseItemMessage.decode
      case 0x11 => game.MoveItemMessage.decode
      case 0x12 => game.ChatMsg.decode
      case 0x13 => game.CharacterNoRecordMessage.decode
      case 0x14 => game.CharacterInfoMessage.decode
      case 0x15 => noDecoder(UnknownMessage21)
      case 0x16 => game.BindPlayerMessage.decode
      case 0x17 => game.ObjectCreateMessage.decode
      // 0x18
      case 0x18 => game.ObjectCreateDetailedMessage.decode
      case 0x19 => game.ObjectDeleteMessage.decode
      case 0x1a => game.PingMsg.decode
      case 0x1b => game.VehicleStateMessage.decode
      case 0x1c => game.FrameVehicleStateMessage.decode
      case 0x1d => game.GenericObjectStateMsg.decode
      case 0x1e => game.ChildObjectStateMessage.decode
      case 0x1f => game.ActionResultMessage.decode

      // OPCODES 0x20-2f
      case 0x20 => noDecoder(UnknownMessage32)
      case 0x21 => game.ActionProgressMessage.decode
      case 0x22 => game.ActionCancelMessage.decode
      case 0x23 => noDecoder(ActionCancelAcknowledgeMessage)
      case 0x24 => game.SetEmpireMessage.decode
      case 0x25 => game.EmoteMsg.decode
      case 0x26 => game.UnuseItemMessage.decode
      case 0x27 => game.ObjectDetachMessage.decode
      // 0x28
      case 0x28 => game.CreateShortcutMessage.decode
      case 0x29 => game.ChangeShortcutBankMessage.decode
      case 0x2a => game.ObjectAttachMessage.decode
      case 0x2b => noDecoder(UnknownMessage43)
      case 0x2c => game.PlanetsideAttributeMessage.decode
      case 0x2d => game.RequestDestroyMessage.decode
      case 0x2e => noDecoder(UnknownMessage46)
      case 0x2f => game.CharacterCreateRequestMessage.decode

      // OPCODES 0x30-3f
      case 0x30 => game.CharacterRequestMessage.decode
      case 0x31 => game.LoadMapMessage.decode
      case 0x32 => game.SetCurrentAvatarMessage.decode
      case 0x33 => game.ObjectHeldMessage.decode
      case 0x34 => game.WeaponFireMessage.decode
      case 0x35 => game.AvatarJumpMessage.decode
      case 0x36 => game.PickupItemMessage.decode
      case 0x37 => game.DropItemMessage.decode
      // 0x38
      case 0x38 => game.InventoryStateMessage.decode
      case 0x39 => game.ChangeFireStateMessage_Start.decode
      case 0x3a => game.ChangeFireStateMessage_Stop.decode
      case 0x3b => noDecoder(UnknownMessage59)
      case 0x3c => game.GenericCollisionMsg.decode
      case 0x3d => game.QuantityUpdateMessage.decode
      case 0x3e => game.ArmorChangedMessage.decode
      case 0x3f => game.ProjectileStateMessage.decode

      // OPCODES 0x40-4f
      case 0x40 => game.MountVehicleCargoMsg.decode
      case 0x41 => game.DismountVehicleCargoMsg.decode
      case 0x42 => game.CargoMountPointStatusMessage.decode
      case 0x43 => game.BeginZoningMessage.decode
      case 0x44 => game.ItemTransactionMessage.decode
      case 0x45 => game.ItemTransactionResultMessage.decode
      case 0x46 => game.ChangeFireModeMessage.decode
      case 0x47 => game.ChangeAmmoMessage.decode
      // 0x48
      case 0x48 => game.TimeOfDayMessage.decode
      case 0x49 => noDecoder(UnknownMessage73)
      case 0x4a => game.SpawnRequestMessage.decode
      case 0x4b => game.DeployRequestMessage.decode
      case 0x4c => noDecoder(UnknownMessage76)
      case 0x4d => game.RepairMessage.decode
      case 0x4e => game.ServerVehicleOverrideMsg.decode
      case 0x4f => game.LashMessage.decode

      // OPCODES 0x50-5f
      case 0x50 => game.TargetingInfoMessage.decode
      case 0x51 => game.TriggerEffectMessage.decode
      case 0x52 => game.WeaponDryFireMessage.decode
      case 0x53 => game.DroppodLaunchRequestMessage.decode
      case 0x54 => game.HackMessage.decode
      case 0x55 => game.DroppodLaunchResponseMessage.decode
      case 0x56 => game.GenericObjectActionMessage.decode
      case 0x57 => game.AvatarVehicleTimerMessage.decode
      // 0x58
      case 0x58 => game.AvatarImplantMessage.decode
      case 0x59 => noDecoder(UnknownMessage89)
      case 0x5a => game.DelayedPathMountMsg.decode
      case 0x5b => game.OrbitalShuttleTimeMsg.decode
      case 0x5c => noDecoder(AIDamage)
      case 0x5d => game.DeployObjectMessage.decode
      case 0x5e => game.FavoritesRequest.decode
      case 0x5f => noDecoder(FavoritesResponse)

      // OPCODES 0x60-6f
      case 0x60 => game.FavoritesMessage.decode
      case 0x61 => game.ObjectDetectedMessage.decode
      case 0x62 => game.SplashHitMessage.decode
      case 0x63 => game.SetChatFilterMessage.decode
      case 0x64 => game.AvatarSearchCriteriaMessage.decode
      case 0x65 => noDecoder(AvatarSearchResponse)
      case 0x66 => game.WeaponJammedMessage.decode
      case 0x67 => noDecoder(LinkDeadAwarenessMsg)
      // 0x68
      case 0x68 => game.DroppodFreefallingMessage.decode
      case 0x69 => game.AvatarFirstTimeEventMessage.decode
      case 0x6a => game.AggravatedDamageMessage.decode
      case 0x6b => game.TriggerSoundMessage.decode
      case 0x6c => game.LootItemMessage.decode
      case 0x6d => game.VehicleSubStateMessage.decode
      case 0x6e => game.SquadMembershipRequest.decode
      case 0x6f => game.SquadMembershipResponse.decode

      // OPCODES 0x70-7f
      case 0x70 => game.SquadMemberEvent.decode
      case 0x71 => noDecoder(PlatoonEvent)
      case 0x72 => game.FriendsRequest.decode
      case 0x73 => game.FriendsResponse.decode
      case 0x74 => game.TriggerEnvironmentalDamageMessage.decode
      case 0x75 => game.TrainingZoneMessage.decode
      case 0x76 => game.DeployableObjectsInfoMessage.decode
      case 0x77 => game.SquadState.decode
      // 0x78
      case 0x78 => game.OxygenStateMessage.decode
      case 0x79 => game.TradeMessage.decode
      case 0x7a => noDecoder(UnknownMessage122)
      case 0x7b => game.DamageFeedbackMessage.decode
      case 0x7c => game.DismountBuildingMsg.decode
      case 0x7d => noDecoder(UnknownMessage125)
      case 0x7e => noDecoder(UnknownMessage126)
      case 0x7f => game.AvatarStatisticsMessage.decode

      // OPCODES 0x80-8f
      case 0x80 => noDecoder(GenericObjectAction2Message)
      case 0x81 => game.DestroyDisplayMessage.decode
      case 0x82 => noDecoder(TriggerBotAction)
      case 0x83 => game.SquadWaypointRequest.decode
      case 0x84 => game.SquadWaypointEvent.decode
      case 0x85 => game.OffshoreVehicleMessage.decode
      case 0x86 => game.ObjectDeployedMessage.decode
      case 0x87 => noDecoder(ObjectDeployedCountMessage)
      // 0x88
      case 0x88 => game.WeaponDelayFireMessage.decode
      case 0x89 => game.BugReportMessage.decode
      case 0x8a => game.PlayerStasisMessage.decode
      case 0x8b => noDecoder(UnknownMessage139)
      case 0x8c => noDecoder(OutfitMembershipRequest)
      case 0x8d => noDecoder(OutfitMembershipResponse)
      case 0x8e => game.OutfitRequest.decode
      case 0x8f => noDecoder(OutfitEvent)

      // OPCODES 0x90-9f
      case 0x90 => noDecoder(OutfitMemberEvent)
      case 0x91 => noDecoder(OutfitMemberUpdate)
      case 0x92 => game.PlanetsideStringAttributeMessage.decode
      case 0x93 => game.DataChallengeMessage.decode
      case 0x94 => game.DataChallengeMessageResp.decode
      case 0x95 => game.WeatherMessage.decode
      case 0x96 => game.SimDataChallenge.decode
      case 0x97 => game.SimDataChallengeResp.decode
      // 0x98
      case 0x98 => noDecoder(OutfitListEvent)
      case 0x99 => noDecoder(EmpireIncentivesMessage)
      case 0x9a => game.InvalidTerrainMessage.decode
      case 0x9b => noDecoder(SyncMessage)
      case 0x9c => noDecoder(DebugDrawMessage)
      case 0x9d => noDecoder(SoulMarkMessage)
      case 0x9e => noDecoder(UplinkPositionEvent)
      case 0x9f => game.HotSpotUpdateMessage.decode

      // OPCODES 0xa0-af
      case 0xa0 => game.BuildingInfoUpdateMessage.decode
      case 0xa1 => game.FireHintMessage.decode
      case 0xa2 => noDecoder(UplinkRequest)
      case 0xa3 => noDecoder(UplinkResponse)
      case 0xa4 => game.WarpgateRequest.decode
      case 0xa5 => noDecoder(WarpgateResponse)
      case 0xa6 => game.DamageWithPositionMessage.decode
      case 0xa7 => game.GenericActionMessage.decode
      // 0xa8
      case 0xa8 => game.ContinentalLockUpdateMessage.decode
      case 0xa9 => game.AvatarGrenadeStateMessage.decode
      case 0xaa => noDecoder(UnknownMessage170)
      case 0xab => noDecoder(UnknownMessage171)
      case 0xac => game.ReleaseAvatarRequestMessage.decode
      case 0xad => game.AvatarDeadStateMessage.decode
      case 0xae => noDecoder(CSAssistMessage)
      case 0xaf => noDecoder(CSAssistCommentMessage)

      // OPCODES 0xb0-bf
      case 0xb0 => game.VoiceHostRequest.decode
      case 0xb1 => game.VoiceHostKill.decode
      case 0xb2 => game.VoiceHostInfo.decode
      case 0xb3 => game.BattleplanMessage.decode
      case 0xb4 => game.BattleExperienceMessage.decode
      case 0xb5 => game.TargetingImplantRequest.decode
      case 0xb6 => game.ZonePopulationUpdateMessage.decode
      case 0xb7 => game.DisconnectMessage.decode
      // 0xb8
      case 0xb8 => game.ExperienceAddedMessage.decode
      case 0xb9 => game.OrbitalStrikeWaypointMessage.decode
      case 0xba => game.KeepAliveMessage.decode
      case 0xbb => noDecoder(MapObjectStateBlockMessage)
      case 0xbc => noDecoder(SnoopMsg)
      case 0xbd => game.PlayerStateMessageUpstream.decode
      case 0xbe => game.PlayerStateShiftMessage.decode
      case 0xbf => game.ZipLineMessage.decode

      // OPCODES 0xc0-cf
      case 0xc0 => game.CaptureFlagUpdateMessage.decode
      case 0xc1 => noDecoder(VanuModuleUpdateMessage)
      case 0xc2 => game.FacilityBenefitShieldChargeRequestMessage.decode
      case 0xc3 => game.ProximityTerminalUseMessage.decode
      case 0xc4 => game.QuantityDeltaUpdateMessage.decode
      case 0xc5 => game.ChainLashMessage.decode
      case 0xc6 => game.ZoneInfoMessage.decode
      case 0xc7 => game.LongRangeProjectileInfoMessage.decode
      // 0xc8
      case 0xc8 => game.WeaponLazeTargetPositionMessage.decode
      case 0xc9 => noDecoder(ModuleLimitsMessage)
      case 0xca => noDecoder(OutfitBenefitMessage)
      case 0xcb => noDecoder(EmpireChangeTimeMessage)
      case 0xcc => noDecoder(ClockCalibrationMessage)
      case 0xcd => game.DensityLevelUpdateMessage.decode
      case 0xce => noDecoder(ActOfGodMessage)
      case 0xcf => game.AvatarAwardMessage.decode

      // OPCODES 0xd0-df
      case 0xd0 => noDecoder(UnknownMessage208)
      case 0xd1 => game.DisplayedAwardMessage.decode
      case 0xd2 => game.RespawnAMSInfoMessage.decode
      case 0xd3 => game.ComponentDamageMessage.decode
      case 0xd4 => game.GenericObjectActionAtPositionMessage.decode
      case 0xd5 => game.PropertyOverrideMessage.decode
      case 0xd6 => game.WarpgateLinkOverrideMessage.decode
      case 0xd7 => noDecoder(EmpireBenefitsMessage)
      // 0xd8
      case 0xd8 => noDecoder(ForceEmpireMessage)
      case 0xd9 => game.BroadcastWarpgateUpdateMessage.decode
      case 0xda => noDecoder(UnknownMessage218)
      case 0xdb => noDecoder(SquadMainTerminalMessage)
      case 0xdc => noDecoder(SquadMainTerminalResponseMessage)
      case 0xdd => noDecoder(SquadOrderMessage)
      case 0xde => noDecoder(SquadOrderResponse)
      case 0xdf => game.ZoneLockInfoMessage.decode

      // OPCODES 0xe0-ef
      case 0xe0 => noDecoder(SquadBindInfoMessage)
      case 0xe1 => noDecoder(AudioSequenceMessage)
      case 0xe2 => noDecoder(SquadFacilityBindInfoMessage)
      case 0xe3 => game.ZoneForcedCavernConnectionsMessage.decode
      case 0xe4 => noDecoder(MissionActionMessage)
      case 0xe5 => noDecoder(MissionKillTriggerMessage)
      case 0xe6 => game.ReplicationStreamMessage.decode
      case 0xe7 => game.SquadDefinitionActionMessage.decode
      // 0xe8
      case 0xe8 => game.SquadDetailDefinitionUpdateMessage.decode
      case 0xe9 => noDecoder(TacticsMessage)
      case 0xea => noDecoder(RabbitUpdateMessage)
      case 0xeb => game.SquadInvitationRequestMessage.decode
      case 0xec => game.CharacterKnowledgeMessage.decode
      case 0xed => noDecoder(GameScoreUpdateMessage)
      case 0xee => noDecoder(UnknownMessage238)
      case 0xef => noDecoder(OrderTerminalBugMessage)

      // OPCODES 0xf0-f3
      case 0xf0 => noDecoder(QueueTimedHelpMessage)
      case 0xf1 => game.MailMessage.decode
      case 0xf2 => noDecoder(GameVarUpdate)
      case 0xf3 => noDecoder(ClientCheatedMessage)
      case _    => noDecoder(opcode)
    }

  implicit val codec: Codec[this.Value] = PacketHelpers.createEnumerationCodec(this, uint8L)
}
