diff --git a/common/src/main/scala/net/psforever/packet/GamePacketOpcode.scala b/common/src/main/scala/net/psforever/packet/GamePacketOpcode.scala
index 38f4d140..1f0eb2a5 100644
--- a/common/src/main/scala/net/psforever/packet/GamePacketOpcode.scala
+++ b/common/src/main/scala/net/psforever/packet/GamePacketOpcode.scala
@@ -370,7 +370,7 @@ object GamePacketOpcode extends Enumeration {
case 0x29 => game.ChangeShortcutBankMessage.decode
case 0x2a => game.ObjectAttachMessage.decode
case 0x2b => noDecoder(UnknownMessage43)
- case 0x2c => noDecoder(PlanetsideAttributeMessage)
+ case 0x2c => game.PlanetsideAttributeMessage.decode
case 0x2d => game.RequestDestroyMessage.decode
case 0x2e => noDecoder(UnknownMessage46)
case 0x2f => game.CharacterCreateRequestMessage.decode
diff --git a/common/src/main/scala/net/psforever/packet/game/PlanetsideAttributeMessage.scala b/common/src/main/scala/net/psforever/packet/game/PlanetsideAttributeMessage.scala
new file mode 100644
index 00000000..0818c906
--- /dev/null
+++ b/common/src/main/scala/net/psforever/packet/game/PlanetsideAttributeMessage.scala
@@ -0,0 +1,59 @@
+// Copyright (c) 2016 PSForever.net to present
+package net.psforever.packet.game
+
+import net.psforever.packet.{GamePacketOpcode, Marshallable, PlanetSideGamePacket}
+import scodec.Codec
+import scodec.codecs._
+
+/**
+ * Attribute Type:
+ * Server to client :
+ * `0 - health`
+ * `1 - healthMax`
+ * `2 - stamina`
+ * `3 - staminaMax`
+ * `4 - armor`
+ * `5 - armorMax`
+ * `14 - Something with grief`
+ * `15 - Weapon Lock. Value exemple : 600 to have 1 min lock. Max possible is 30min lock`
+ * `17 - BEP. Value seems to be the same as BattleExperienceMessage`
+ * `18 - CEP.`
+ * `19 - Anchors. Value is 0 to disengage, 1 to engage.`
+ * `24 - Certifications`
+ * `29 - Visible ?! That's not the cloaked effect, Maybe for spectator mode ?. Value is 0 to visible, 1 to invisible.`
+ * `35 - BR. Value is the BR`
+ * `36 - CR. Value is the CR`
+ * `53 - LFS. Value is 1 to flag LFS`
+ * `54 - Player "Aura". Values are : 0 for nothing, 1 for plasma, 2 for ancient, 3 for plasma + ancient,
+ * 4 for LLU?, 5 for plasma + LLU?, 6 for ancient + LLU?, 7 for plasma + ancient + LLU?, 8 for fire,
+ * 9 for plasma + fire, 10 for ancient + fire, 11 for plasma + ancient + fire,
+ * 12 for LLU? + fire, 13 for plasma + LLU? + fire, 14 for ancient + LLU? + fire,
+ * 15 for plasma + ancient + LLU? + fire,`
+ * `55 - "Someone is attempting to Heal you". Value is 1`
+ * `56 - "Someone is attempting to Repair you". Value is 1`
+ * `73 - "You are locked into the Core Beam. Charging your Module now.". Value is 1 to active`
+ * `77 - Cavern Facility Captures. Value is the number of captures`
+ * `78 - Cavern Kills. Value is the number of kills`
+ * `106 - Custom Head`
+ * Client to Server :
+ * `106 - Custom Head`
+ * @param player_guid the player
+ * @param attribute_type na
+ * @param attribute_value na
+ */
+final case class PlanetsideAttributeMessage(player_guid : PlanetSideGUID,
+ attribute_type : Int,
+ attribute_value : Long)
+ extends PlanetSideGamePacket {
+ type Packet = PlanetsideAttributeMessage
+ def opcode = GamePacketOpcode.PlanetsideAttributeMessage
+ def encode = PlanetsideAttributeMessage.encode(this)
+}
+
+object PlanetsideAttributeMessage extends Marshallable[PlanetsideAttributeMessage] {
+ implicit val codec : Codec[PlanetsideAttributeMessage] = (
+ ("player_guid" | PlanetSideGUID.codec) ::
+ ("attribute_type" | uint8L) ::
+ ("attribute_value" | uint32L)
+ ).as[PlanetsideAttributeMessage]
+}
\ No newline at end of file
diff --git a/common/src/test/scala/game/PlanetsideAttributeMessageTest.scala b/common/src/test/scala/game/PlanetsideAttributeMessageTest.scala
new file mode 100644
index 00000000..0706bfa7
--- /dev/null
+++ b/common/src/test/scala/game/PlanetsideAttributeMessageTest.scala
@@ -0,0 +1,30 @@
+// Copyright (c) 2017 PSForever
+package game
+
+import org.specs2.mutable.Specification
+import net.psforever.packet.PacketCoding
+import net.psforever.packet.game._
+import scodec.bits._
+
+class PlanetsideAttributeMessageTest extends Specification {
+ val string = hex"2c d9040458000000"
+
+ "decode" in {
+ PacketCoding.DecodePacket(string).require match {
+ case PlanetsideAttributeMessage(player_guid, attribute_type, attribute_value) =>
+ player_guid mustEqual PlanetSideGUID(1241)
+ attribute_type mustEqual 4
+ attribute_value mustEqual 88
+ case _ =>
+ ko
+ }
+ }
+
+ "encode" in {
+ val msg = PlanetsideAttributeMessage(PlanetSideGUID(1241), 4, 88)
+ val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
+
+ pkt mustEqual string
+ }
+
+}
diff --git a/pslogin/src/main/scala/WorldSessionActor.scala b/pslogin/src/main/scala/WorldSessionActor.scala
index 40da1943..7e87ab8b 100644
--- a/pslogin/src/main/scala/WorldSessionActor.scala
+++ b/pslogin/src/main/scala/WorldSessionActor.scala
@@ -392,6 +392,10 @@ class WorldSessionActor extends Actor with MDCContextAware {
case msg @ BindPlayerMessage(action, bindDesc, unk1, logging, unk2, unk3, unk4, pos) =>
log.info("BindPlayerMessage: " + msg)
+ case msg @ PlanetsideAttributeMessage(avatar_guid, attribute_type, attribute_value) =>
+ log.info("PlanetsideAttributeMessage: "+msg)
+ sendResponse(PacketCoding.CreateGamePacket(0,PlanetsideAttributeMessage(avatar_guid, attribute_type, attribute_value)))
+
case default => log.error(s"Unhandled GamePacket ${pkt}")
}