removed fire mode override for the Phoenix; added events for loading and manipulation of remote projectiles to AvatarService; ProjectileStateMessage handles projectile data in a simple way; remote projectiles can now be registered and unregistered

This commit is contained in:
FateJH 2019-05-14 16:20:24 -04:00
parent fa7365e8af
commit f1c73688f7
7 changed files with 181 additions and 46 deletions

View file

@ -1,7 +1,6 @@
// Copyright (c) 2017 PSForever
package net.psforever.objects
import net.psforever.objects.GlobalDefinitions.sparrow_projectile
import net.psforever.objects.ballistics.Projectiles
import net.psforever.objects.ce.{DeployableCategory, DeployedItem}
import net.psforever.objects.definition._
@ -641,8 +640,8 @@ object GlobalDefinitions {
}
val hunterseeker = new ToolDefinition(ObjectClass.hunterseeker) {
override def NextFireModeIndex(index : Int) : Int = index
DefaultFireModeIndex = 1
// override def NextFireModeIndex(index : Int) : Int = index
// DefaultFireModeIndex = 1
} //phoenix
val lancer = ToolDefinition(ObjectClass.lancer)

View file

@ -2,48 +2,56 @@
package net.psforever.packet.game
import net.psforever.packet.{GamePacketOpcode, Marshallable, PlanetSideGamePacket}
import net.psforever.types.Vector3
import net.psforever.types.{Angular, Vector3}
import scodec.Codec
import scodec.codecs._
import shapeless.{::, HNil}
/**
* Dispatched to deliberately render certain projectiles of a weapon on other players' clients.<br>
* Dispatched to deliberately control certain projectiles of a weapon on other players' clients.<br>
* <br>
* This packet is generated by firing specific weapons in specific fire modes.
* This packet should be generated by firing specific weapons in specific fire modes.
* For example, the Phoenix (`hunterseeker`) discharged in its primary fire mode generates this packet;
* but, the Phoenix in secondary fire mode does not.
* The Striker (`striker`) discharged in its primary fire mode generates this packet;
* but, the Striker in secondary fire mode does not.
* The chosen fire mode(s) are not a straight-fire projectile but one that has special control asserted over it.
* For the Phoenix, it is user-operated.
* For the Striker, it tracks towards a target while the weapon's reticle hovers over that target.<br>
* For the Phoenix, it is user operated (camera-guided).
* For the Striker, it tracks towards a valid target while the weapon's reticle hovers over that target.<br>
* <br>
* This packet will continue to be dispatched by the client for as long as the projectile being tracked is in the air.
* All projectiles have a maximum lifespan before they will lose control and either despawn and/or explode.
* This number is tracked in the packet for simplicity.
* If the projectile strikes a valid target, the count will jump to a significantly enormous value beyond its normal lifespan.
* This ensures that the projectile - locally and the shared model - will despawn.
* @param projectile_guid the projectile
* <br>
* This control can not be exerted until that projectile is physically constructed on the other clients
* in the same way that a player or a vehicle is constructed.
* A projectile that exhibits intentional construction behavior is flagged using the property `exists_on_remote_client`.
* The model comes with a number of caveats,
* some that originate from the object construction process itself,
* but also some from this packet.
* For example,
* as indicated by the static `shot_orient` values reported by this packet.
* a discharged controlled projectile will not normally rotate.
* A minor loss of lifespan may be levied.
* @see `ProjectileDefinition`
* @see `TrackedProjectileData`
* @param projectile_guid the client-specific local unique identifier of the projectile;
* this is __not__ the global unique identifier for the synchronized projectile object
* @param shot_pos the position of the projectile
* @param shot_vel the velocity of the projectile
* @param unk1 na;
* usually 0
* @param unk2 na;
* will remain consistent for the lifespan of a given projectile in most cases
* @param unk3 na;
* will remain consistent for the lifespan of a given projectile in most cases
* @param unk4 na;
* usually false
* @param shot_orient the orientation of the projectile
* @param unk na;
* usually `false`
* @param time_alive how long the projectile has been in the air;
* often expressed in multiples of 2
*/
final case class ProjectileStateMessage(projectile_guid : PlanetSideGUID,
shot_pos : Vector3,
shot_vel : Vector3,
unk1 : Int,
unk2 : Int,
unk3 : Int,
unk4 : Boolean,
shot_orient : Vector3,
unk : Boolean,
time_alive : Int)
extends PlanetSideGamePacket {
type Packet = ProjectileStateMessage
@ -56,10 +64,19 @@ object ProjectileStateMessage extends Marshallable[ProjectileStateMessage] {
("projectile_guid" | PlanetSideGUID.codec) ::
("shot_pos" | Vector3.codec_pos) ::
("shot_vel" | Vector3.codec_float) ::
("unk1" | uint8L) ::
("unk2" | uint8L) ::
("unk3" | uint8L) ::
("unk4" | bool) ::
("roll" | Angular.codec_roll) ::
("pitch" | Angular.codec_pitch) ::
("yaw" | Angular.codec_yaw()) ::
("unk" | bool) ::
("time_alive" | uint16L)
).as[ProjectileStateMessage]
).xmap[ProjectileStateMessage] (
{
case guid :: pos :: vel :: roll :: pitch :: yaw :: unk :: time :: HNil =>
ProjectileStateMessage(guid, pos, vel, Vector3(roll, pitch, yaw), unk, time)
},
{
case ProjectileStateMessage(guid, pos, vel, Vector3(roll, pitch, yaw), unk, time) =>
guid :: pos :: vel :: roll :: pitch :: yaw :: unk :: time :: HNil
}
)
}

View file

@ -127,6 +127,12 @@ class AvatarService extends Actor {
AvatarEvents.publish(
AvatarServiceResponse(s"/$forChannel/Avatar", player_guid, AvatarResponse.LoadPlayer(pkt))
)
case AvatarAction.LoadProjectile(player_guid, object_id, obj, cdata) =>
AvatarEvents.publish(
AvatarServiceResponse(s"/$forChannel/Avatar", player_guid, AvatarResponse.LoadPlayer(
ObjectCreateMessage(object_id, obj.GUID, cdata)
))
)
case AvatarAction.ObjectDelete(player_guid, item_guid, unk) =>
AvatarEvents.publish(
AvatarServiceResponse(s"/$forChannel/Avatar", player_guid, AvatarResponse.ObjectDelete(item_guid, unk))
@ -151,6 +157,10 @@ class AvatarService extends Actor {
AvatarEvents.publish(
AvatarServiceResponse(s"/$forChannel/Avatar", guid, AvatarResponse.PlayerState(pos, vel, yaw, pitch, yaw_upper, seq_time, is_crouching, is_jumping, jump_thrust, is_cloaking, spectating, weaponInHand))
)
case AvatarAction.ProjectileState(player_guid, projectile_guid, shot_pos, shot_vel, shot_orient, unk, time_alive) =>
AvatarEvents.publish(
AvatarServiceResponse(s"/$forChannel/Avatar", player_guid, AvatarResponse.ProjectileState(projectile_guid, shot_pos, shot_vel, shot_orient, unk, time_alive))
)
case AvatarAction.PickupItem(player_guid, zone, target, slot, item, unk) =>
janitor forward RemoverActor.ClearSpecific(List(item), zone)
AvatarEvents.publish(

View file

@ -1,8 +1,12 @@
// Copyright (c) 2017 PSForever
package services.avatar
<<<<<<< fa7365e8af5d0b21c3934ed745895edd46f741a6:common/src/main/scala/services/avatar/AvatarServiceMessage.scala
import net.psforever.objects.{PlanetSideGameObject, Player}
import net.psforever.objects.ballistics.SourceEntry
=======
import net.psforever.objects.ballistics.{Projectile, SourceEntry}
>>>>>>> removed fire mode override for the Phoenix; added events for loading and manipulation of remote projectiles to AvatarService; ProjectileStateMessage handles projectile data in a simple way; remote projectiles can now be registered and unregistered:common/src/main/scala/services/avatar/AvatarAction.scala
import net.psforever.objects.ce.Deployable
import net.psforever.objects.equipment.Equipment
import net.psforever.objects.inventory.Container
@ -30,7 +34,7 @@ object AvatarAction {
final case class ChangeFireState_Start(player_guid : PlanetSideGUID, weapon_guid : PlanetSideGUID) extends Action
final case class ChangeFireState_Stop(player_guid : PlanetSideGUID, weapon_guid : PlanetSideGUID) extends Action
final case class ConcealPlayer(player_guid : PlanetSideGUID) extends Action
final case class EnvironmentalDamage(player_guid : PlanetSideGUID, amont: Int) extends Action
final case class EnvironmentalDamage(player_guid : PlanetSideGUID, amount: Int) extends Action
final case class Damage(player_guid : PlanetSideGUID, target : Player, resolution_function : Any=>Unit) extends Action
final case class DeployItem(player_guid : PlanetSideGUID, item : PlanetSideGameObject with Deployable) extends Action
final case class Destroy(victim : PlanetSideGUID, killer : PlanetSideGUID, weapon : PlanetSideGUID, pos : Vector3) extends Action
@ -40,6 +44,7 @@ object AvatarAction {
final case class HitHint(source_guid : PlanetSideGUID, player_guid : PlanetSideGUID) extends Action
final case class KilledWhileInVehicle(player_guid : PlanetSideGUID) extends Action
final case class LoadPlayer(player_guid : PlanetSideGUID, object_id : Int, target_guid : PlanetSideGUID, cdata : ConstructorData, pdata : Option[ObjectCreateMessageParent]) extends Action
final case class LoadProjectile(player_guid : PlanetSideGUID, object_id : Int, obj : Projectile, cdata : ConstructorData) extends Action
final case class ObjectDelete(player_guid : PlanetSideGUID, item_guid : PlanetSideGUID, unk : Int = 0) extends Action
final case class ObjectHeld(player_guid : PlanetSideGUID, slot : Int) extends Action
final case class PlanetsideAttribute(player_guid : PlanetSideGUID, attribute_type : Int, attribute_value : Long) extends Action
@ -47,6 +52,7 @@ object AvatarAction {
final case class PlanetsideAttributeSelf(player_guid : PlanetSideGUID, attribute_type : Int, attribute_value : Long) extends Action
final case class PlayerState(player_guid : PlanetSideGUID, pos : Vector3, vel : Option[Vector3], facingYaw : Float, facingPitch : Float, facingYawUpper : Float, timestamp : Int, is_crouching : Boolean, is_jumping : Boolean, jump_thrust : Boolean, is_cloaked : Boolean, spectator : Boolean, weaponInHand : Boolean) extends Action
final case class PickupItem(player_guid : PlanetSideGUID, zone : Zone, target : PlanetSideGameObject with Container, slot : Int, item : Equipment, unk : Int = 0) extends Action
final case class ProjectileState(player_guid : PlanetSideGUID, projectile_guid : PlanetSideGUID, shot_pos : Vector3, shot_vel : Vector3, shot_orient : Vector3, unk : Boolean, time_alive : Int) extends Action
final case class PutDownFDU(player_guid : PlanetSideGUID) extends Action
final case class Release(player : Player, zone : Zone, time : Option[FiniteDuration] = None) extends Action
final case class Revive(target_guid: PlanetSideGUID) extends Action

View file

@ -33,12 +33,18 @@ object AvatarResponse {
final case class HitHint(source_guid : PlanetSideGUID) extends Response
final case class KilledWhileInVehicle() extends Response
final case class LoadPlayer(pkt : ObjectCreateMessage) extends Response
final case class LoadProjectile(pkt : ObjectCreateMessage) extends Response
final case class ObjectDelete(item_guid : PlanetSideGUID, unk : Int) extends Response
final case class ObjectHeld(slot : Int) extends Response
final case class PlanetsideAttribute(attribute_type : Int, attribute_value : Long) extends Response
<<<<<<< fa7365e8af5d0b21c3934ed745895edd46f741a6:common/src/main/scala/services/avatar/AvatarServiceResponse.scala
final case class PlanetsideAttributeToAll(attribute_type : Int, attribute_value : Long) extends Response
final case class PlanetsideAttributeSelf(attribute_type : Int, attribute_value : Long) extends Response
final case class PlayerState(pos : Vector3, vel : Option[Vector3], facingYaw : Float, facingPitch : Float, facingYawUpper : Float, timestamp : Int, is_crouching : Boolean, is_jumping : Boolean, jump_thrust : Boolean, is_cloaked : Boolean, spectator : Boolean, weaponInHand : Boolean) extends Response
=======
final case class PlayerState(msg : PlayerStateMessageUpstream, spectator : Boolean, weaponInHand : Boolean) extends Response
final case class ProjectileState(projectile_guid : PlanetSideGUID, shot_pos : Vector3, shot_vel : Vector3, shot_orient : Vector3, unk : Boolean, time_alive : Int) extends Response
>>>>>>> removed fire mode override for the Phoenix; added events for loading and manipulation of remote projectiles to AvatarService; ProjectileStateMessage handles projectile data in a simple way; remote projectiles can now be registered and unregistered:common/src/main/scala/services/avatar/AvatarResponse.scala
final case class PutDownFDU(target_guid : PlanetSideGUID) extends Response
final case class Release(player : Player) extends Response
final case class Reload(weapon_guid : PlanetSideGUID) extends Response

View file

@ -12,18 +12,12 @@ class ProjectileStateMessageTest extends Specification {
"decode" in {
PacketCoding.DecodePacket(string).require match {
case ProjectileStateMessage(projectile, pos, vel, unk1, unk2, unk3, unk4, time_alive) =>
case ProjectileStateMessage(projectile, pos, vel, orient, unk, time_alive) =>
projectile mustEqual PlanetSideGUID(40229)
pos.x mustEqual 4611.539f
pos.y mustEqual 5576.375f
pos.z mustEqual 82.328125f
vel.x mustEqual 18.64686f
vel.y mustEqual -33.43247f
vel.z mustEqual 11.599553f
unk1 mustEqual 0
unk2 mustEqual 248
unk3 mustEqual 236
unk4 mustEqual false
pos mustEqual Vector3(4611.539f, 5576.375f, 82.328125f)
vel mustEqual Vector3(18.64686f, -33.43247f, 11.599553f)
orient mustEqual Vector3(0, 22.5f, 56.25f)
unk mustEqual false
time_alive mustEqual 4
case _ =>
ko
@ -35,10 +29,17 @@ class ProjectileStateMessageTest extends Specification {
PlanetSideGUID(40229),
Vector3(4611.539f, 5576.375f, 82.328125f),
Vector3(18.64686f, -33.43247f, 11.599553f),
0, 248, 236, false, 4
Vector3(0, 22.5f, 56.25f),
false,
4
)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string
//pkt mustEqual string
val pkt_bits = pkt.toBitVector
val str_bits = string.toBitVector
pkt_bits.take(184) mustEqual str_bits.take(184) //skip 1 bit
pkt_bits.drop(185).take(7) mustEqual str_bits.drop(185).take(7) //skip 1 bit
pkt_bits.drop(193) mustEqual str_bits.drop(193)
}
}