mirror of
https://github.com/psforever/PSF-LoginServer.git
synced 2026-01-20 02:54:46 +00:00
Merge pull request #145 from Fate-JH/trigger-effect
Packet: TriggerEffectMessage
This commit is contained in:
commit
32c094b86d
|
|
@ -415,7 +415,7 @@ object GamePacketOpcode extends Enumeration {
|
|||
|
||||
// OPCODES 0x50-5f
|
||||
case 0x50 => game.TargetingInfoMessage.decode
|
||||
case 0x51 => noDecoder(TriggerEffectMessage)
|
||||
case 0x51 => game.TriggerEffectMessage.decode
|
||||
case 0x52 => game.WeaponDryFireMessage.decode
|
||||
case 0x53 => noDecoder(DroppodLaunchRequestMessage)
|
||||
case 0x54 => noDecoder(HackMessage)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,83 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package net.psforever.packet.game
|
||||
|
||||
import net.psforever.packet.{GamePacketOpcode, Marshallable, PacketHelpers, PlanetSideGamePacket}
|
||||
import net.psforever.types.Vector3
|
||||
import scodec.Codec
|
||||
import scodec.codecs._
|
||||
|
||||
/**
|
||||
* na
|
||||
* @param unk1 na;
|
||||
* `true` to apply the effect usually
|
||||
* @param unk2 na
|
||||
*/
|
||||
final case class TriggeredEffect(unk1 : Boolean,
|
||||
unk2 : Long)
|
||||
|
||||
/**
|
||||
* Activate an effect that is not directly associated with an existing game object.
|
||||
* Without a game object from which to inherit position and orientation, those explicit parameters must be provided.
|
||||
* @param pos the position in the game world
|
||||
* @param roll the amount of roll that affects orientation
|
||||
* @param pitch the amount of pitch that affects orientation
|
||||
* @param yaw the amount of yaw that affects orientation
|
||||
*/
|
||||
final case class TriggeredEffectLocation(pos : Vector3,
|
||||
roll : Int,
|
||||
pitch : Int,
|
||||
yaw : Int)
|
||||
|
||||
/**
|
||||
* Dispatched by the server to cause a client to display a special graphical effect.<br>
|
||||
* <br>
|
||||
* The effect being triggered can be based around a specific game object or replayed freely, absent of an anchoring object.
|
||||
* If object-based then the kinds of effects that can be activated are specific to the object.
|
||||
* If unbound, then a wider range of effects can be displayed.
|
||||
* Regardless, one category will rarely ever be activated under the same valid conditions of the other category.
|
||||
* For example, the effect "on" will only work on objects that accept "on" normally, like a deployed `motionalarmsensor`.
|
||||
* The effect "spawn_object_effect" can be applied anywhere in the environment;
|
||||
* but, it can not be activated in conjunction with an existing object.
|
||||
* @param obj an object that accepts the effect
|
||||
* @param effect the name of the effect
|
||||
* @param unk na;
|
||||
* when activating an effect on an existing object
|
||||
* @param location an optional position where the effect will be displayed;
|
||||
* when activating an effect independently
|
||||
*/
|
||||
final case class TriggerEffectMessage(obj : PlanetSideGUID,
|
||||
effect : String,
|
||||
unk : Option[TriggeredEffect] = None,
|
||||
location : Option[TriggeredEffectLocation] = None
|
||||
) extends PlanetSideGamePacket {
|
||||
type Packet = TriggerEffectMessage
|
||||
def opcode = GamePacketOpcode.TriggerEffectMessage
|
||||
def encode = TriggerEffectMessage.encode(this)
|
||||
}
|
||||
|
||||
object TriggerEffectMessage extends Marshallable[TriggerEffectMessage] {
|
||||
/**
|
||||
* A `Codec` for `TriggeredEffect` data.
|
||||
*/
|
||||
private val effect_codec : Codec[TriggeredEffect] = (
|
||||
("unk1" | bool) ::
|
||||
("unk2" | uint32L)
|
||||
).as[TriggeredEffect]
|
||||
|
||||
/**
|
||||
* A `Codec` for `TriggeredEffectLocation` data.
|
||||
*/
|
||||
private val effect_location_codec : Codec[TriggeredEffectLocation] = (
|
||||
("pos" | Vector3.codec_pos) ::
|
||||
("roll" | uint8L) ::
|
||||
("pitch" | uint8L) ::
|
||||
("yaw" | uint8L)
|
||||
).as[TriggeredEffectLocation]
|
||||
|
||||
implicit val codec : Codec[TriggerEffectMessage] = (
|
||||
("obj" | PlanetSideGUID.codec) >>:~ { obj =>
|
||||
("effect" | PacketHelpers.encodedString) ::
|
||||
optional(bool, "unk" | effect_codec) ::
|
||||
conditional(obj.guid == 0, "location" | effect_location_codec)
|
||||
}).as[TriggerEffectMessage]
|
||||
}
|
||||
73
common/src/test/scala/game/TriggerEffectMessageTest.scala
Normal file
73
common/src/test/scala/game/TriggerEffectMessageTest.scala
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package game
|
||||
|
||||
import org.specs2.mutable._
|
||||
import net.psforever.packet._
|
||||
import net.psforever.packet.game._
|
||||
import net.psforever.types.Vector3
|
||||
import scodec.bits._
|
||||
|
||||
class TriggerEffectMessageTest extends Specification {
|
||||
val string_motionalarmsensor = hex"51 970B 82 6F6E FA00C00000"
|
||||
val string_boomer = hex"51 0000 93 737061776E5F6F626A6563745F656666656374 417BB2CB3B4F8E00000000"
|
||||
|
||||
"decode (motion alarm sensor)" in {
|
||||
PacketCoding.DecodePacket(string_motionalarmsensor).require match {
|
||||
case TriggerEffectMessage(guid, effect, unk, location) =>
|
||||
guid mustEqual PlanetSideGUID(2967)
|
||||
effect mustEqual "on"
|
||||
unk.isDefined mustEqual true
|
||||
unk.get.unk1 mustEqual true
|
||||
unk.get.unk2 mustEqual 1000L
|
||||
location.isDefined mustEqual false
|
||||
case _ =>
|
||||
ko
|
||||
}
|
||||
}
|
||||
|
||||
"decode (boomer)" in {
|
||||
PacketCoding.DecodePacket(string_boomer).require match {
|
||||
case TriggerEffectMessage(guid, effect, unk, location) =>
|
||||
guid mustEqual PlanetSideGUID(0)
|
||||
effect mustEqual "spawn_object_effect"
|
||||
unk.isDefined mustEqual false
|
||||
location.isDefined mustEqual true
|
||||
location.get.pos.x mustEqual 3567.0156f
|
||||
location.get.pos.y mustEqual 3278.6953f
|
||||
location.get.pos.z mustEqual 114.484375f
|
||||
location.get.roll mustEqual 0
|
||||
location.get.pitch mustEqual 0
|
||||
location.get.yaw mustEqual 0
|
||||
case _ =>
|
||||
ko
|
||||
}
|
||||
}
|
||||
|
||||
"encode (motion alarm sensor)" in {
|
||||
val msg = TriggerEffectMessage(
|
||||
PlanetSideGUID(2967),
|
||||
"on",
|
||||
Some(TriggeredEffect(true, 1000L)),
|
||||
None
|
||||
)
|
||||
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
|
||||
|
||||
pkt mustEqual string_motionalarmsensor
|
||||
}
|
||||
|
||||
"encode (boomer)" in {
|
||||
val msg = TriggerEffectMessage(
|
||||
PlanetSideGUID(0),
|
||||
"spawn_object_effect",
|
||||
None,
|
||||
Some(TriggeredEffectLocation(
|
||||
Vector3(3567.0156f, 3278.6953f, 114.484375f),
|
||||
0, 0, 0
|
||||
))
|
||||
)
|
||||
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
|
||||
|
||||
pkt mustEqual string_boomer
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in a new issue