diff --git a/common/src/main/scala/net/psforever/packet/GamePacketOpcode.scala b/common/src/main/scala/net/psforever/packet/GamePacketOpcode.scala index a7a77e6b..8f6e0097 100644 --- a/common/src/main/scala/net/psforever/packet/GamePacketOpcode.scala +++ b/common/src/main/scala/net/psforever/packet/GamePacketOpcode.scala @@ -352,7 +352,7 @@ object GamePacketOpcode extends Enumeration { case PingMsg => noDecoder(opcode) case VehicleStateMessage => noDecoder(opcode) case FrameVehicleStateMessage => noDecoder(opcode) - case GenericObjectStateMsg => noDecoder(opcode) + case GenericObjectStateMsg => game.GenericObjectStateMsg.decode // OPCODE 30 case ChildObjectStateMessage => noDecoder(opcode) diff --git a/common/src/main/scala/net/psforever/packet/game/GenericObjectStateMsg.scala b/common/src/main/scala/net/psforever/packet/game/GenericObjectStateMsg.scala new file mode 100644 index 00000000..10765972 --- /dev/null +++ b/common/src/main/scala/net/psforever/packet/game/GenericObjectStateMsg.scala @@ -0,0 +1,21 @@ +// Copyright (c) 2016 PSForever.net to present +package net.psforever.packet.game + +import net.psforever.packet.{GamePacketOpcode, Marshallable, PacketHelpers, PlanetSideGamePacket} +import scodec.Codec +import scodec.codecs._ + +final case class GenericObjectStateMsg(object_guid : PlanetSideGUID, + state : Long) + extends PlanetSideGamePacket { + type Packet = GenericObjectStateMsg + def opcode = GamePacketOpcode.GenericObjectStateMsg + def encode = GenericObjectStateMsg.encode(this) +} + +object GenericObjectStateMsg extends Marshallable[GenericObjectStateMsg] { + implicit val codec : Codec[GenericObjectStateMsg] = ( + ("object_guid" | PlanetSideGUID.codec) :: + ("state" | uint32L) + ).as[GenericObjectStateMsg] +} diff --git a/common/src/test/scala/GamePacketTest.scala b/common/src/test/scala/GamePacketTest.scala index fbad96c7..c2ce00bc 100644 --- a/common/src/test/scala/GamePacketTest.scala +++ b/common/src/test/scala/GamePacketTest.scala @@ -498,5 +498,26 @@ class GamePacketTest extends Specification { pkt mustEqual string } } + + "GenericObjectStateMsg" should { + val string = hex"1D 6401 10000000" + + "decode" in { + PacketCoding.DecodePacket(string).require match { + case GenericObjectStateMsg(object_guid, state) => + object_guid mustEqual PlanetSideGUID(356) + state mustEqual 16 + case default => + ko + } + } + + "encode" in { + val msg = GenericObjectStateMsg(PlanetSideGUID(356), 16) + 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 0b8cb6c4..7d059bff 100644 --- a/pslogin/src/main/scala/WorldSessionActor.scala +++ b/pslogin/src/main/scala/WorldSessionActor.scala @@ -197,6 +197,11 @@ class WorldSessionActor extends Actor with MDCContextAware { // TODO: Not all fields in the response are identical to source in real packet logs (but seems to be ok) // TODO: Not all incoming UseItemMessage's respond with another UseItemMessage (i.e. doors only send out GenericObjectStateMsg) sendResponse(PacketCoding.CreateGamePacket(0, UseItemMessage(avatar_guid, unk1, object_guid, unk2, unk3, unk4, unk5, unk6, unk7, unk8, unk9))) + // TODO: This should only actually be sent to doors upon opening; may break non-door items upon use + sendResponse(PacketCoding.CreateGamePacket(0, GenericObjectStateMsg(object_guid, 16))) + + case msg @ GenericObjectStateMsg(object_guid, unk1) => + log.info("GenericObjectState: " + msg) case default => log.debug(s"Unhandled GamePacket ${pkt}") }