proper PSM encoding/decoding; normal and alternate projectile flight handling; auto lock field on projectiles, to indicate whether that projectile should produce a warning message on the target's side when weapon is pointed at the target; business logic in WSA

This commit is contained in:
FateJH 2019-11-04 09:21:36 -05:00
parent d1ba353cad
commit 043512d6a3
8 changed files with 129 additions and 57 deletions

View file

@ -2160,6 +2160,7 @@ object GlobalDefinitions {
aphelion_starfire_projectile.ProjectileDamageType = DamageType.Aggravated aphelion_starfire_projectile.ProjectileDamageType = DamageType.Aggravated
aphelion_starfire_projectile.ExistsOnRemoteClients = true aphelion_starfire_projectile.ExistsOnRemoteClients = true
aphelion_starfire_projectile.RemoteClientData = (39577, 249) //starfire_projectile data aphelion_starfire_projectile.RemoteClientData = (39577, 249) //starfire_projectile data
aphelion_starfire_projectile.AutoLock = true
aphelion_starfire_projectile.Packet = projectileConverter aphelion_starfire_projectile.Packet = projectileConverter
ProjectileDefinition.CalculateDerivedFields(aphelion_starfire_projectile) ProjectileDefinition.CalculateDerivedFields(aphelion_starfire_projectile)
@ -3022,6 +3023,7 @@ object GlobalDefinitions {
peregrine_sparrow_projectile.Lifespan = 7.5f peregrine_sparrow_projectile.Lifespan = 7.5f
peregrine_sparrow_projectile.ExistsOnRemoteClients = true peregrine_sparrow_projectile.ExistsOnRemoteClients = true
peregrine_sparrow_projectile.RemoteClientData = (13107, 187) //sparrow_projectile data peregrine_sparrow_projectile.RemoteClientData = (13107, 187) //sparrow_projectile data
peregrine_sparrow_projectile.AutoLock = true
peregrine_sparrow_projectile.Packet = projectileConverter peregrine_sparrow_projectile.Packet = projectileConverter
ProjectileDefinition.CalculateDerivedFields(peregrine_sparrow_projectile) ProjectileDefinition.CalculateDerivedFields(peregrine_sparrow_projectile)
@ -3355,6 +3357,7 @@ object GlobalDefinitions {
sparrow_projectile.Lifespan = 5.85f sparrow_projectile.Lifespan = 5.85f
sparrow_projectile.ExistsOnRemoteClients = true sparrow_projectile.ExistsOnRemoteClients = true
sparrow_projectile.RemoteClientData = (13107, 187) sparrow_projectile.RemoteClientData = (13107, 187)
sparrow_projectile.AutoLock = true
sparrow_projectile.Packet = projectileConverter sparrow_projectile.Packet = projectileConverter
ProjectileDefinition.CalculateDerivedFields(sparrow_projectile) ProjectileDefinition.CalculateDerivedFields(sparrow_projectile)
@ -3372,6 +3375,7 @@ object GlobalDefinitions {
sparrow_secondary_projectile.Lifespan = 5.85f sparrow_secondary_projectile.Lifespan = 5.85f
sparrow_secondary_projectile.ExistsOnRemoteClients = true sparrow_secondary_projectile.ExistsOnRemoteClients = true
sparrow_secondary_projectile.RemoteClientData = (13107, 187) sparrow_secondary_projectile.RemoteClientData = (13107, 187)
sparrow_secondary_projectile.AutoLock = true
sparrow_secondary_projectile.Packet = projectileConverter sparrow_secondary_projectile.Packet = projectileConverter
ProjectileDefinition.CalculateDerivedFields(sparrow_secondary_projectile) ProjectileDefinition.CalculateDerivedFields(sparrow_secondary_projectile)
@ -3425,6 +3429,7 @@ object GlobalDefinitions {
starfire_projectile.Lifespan = 7.8f starfire_projectile.Lifespan = 7.8f
starfire_projectile.ExistsOnRemoteClients = true starfire_projectile.ExistsOnRemoteClients = true
starfire_projectile.RemoteClientData = (39577, 249) starfire_projectile.RemoteClientData = (39577, 249)
starfire_projectile.AutoLock = true
starfire_projectile.Packet = projectileConverter starfire_projectile.Packet = projectileConverter
ProjectileDefinition.CalculateDerivedFields(starfire_projectile) ProjectileDefinition.CalculateDerivedFields(starfire_projectile)
@ -3459,6 +3464,7 @@ object GlobalDefinitions {
striker_missile_targeting_projectile.Lifespan = 4.2f striker_missile_targeting_projectile.Lifespan = 4.2f
striker_missile_targeting_projectile.ExistsOnRemoteClients = true striker_missile_targeting_projectile.ExistsOnRemoteClients = true
striker_missile_targeting_projectile.RemoteClientData = (26214, 134) striker_missile_targeting_projectile.RemoteClientData = (26214, 134)
striker_missile_targeting_projectile.AutoLock = true
striker_missile_targeting_projectile.Packet = projectileConverter striker_missile_targeting_projectile.Packet = projectileConverter
ProjectileDefinition.CalculateDerivedFields(striker_missile_targeting_projectile) ProjectileDefinition.CalculateDerivedFields(striker_missile_targeting_projectile)
@ -3549,6 +3555,7 @@ object GlobalDefinitions {
wasp_rocket_projectile.Lifespan = 6.5f wasp_rocket_projectile.Lifespan = 6.5f
wasp_rocket_projectile.ExistsOnRemoteClients = true wasp_rocket_projectile.ExistsOnRemoteClients = true
wasp_rocket_projectile.RemoteClientData = (0, 208) wasp_rocket_projectile.RemoteClientData = (0, 208)
wasp_rocket_projectile.AutoLock = true
wasp_rocket_projectile.Packet = projectileConverter wasp_rocket_projectile.Packet = projectileConverter
ProjectileDefinition.CalculateDerivedFields(wasp_rocket_projectile) ProjectileDefinition.CalculateDerivedFields(wasp_rocket_projectile)

View file

@ -25,6 +25,7 @@ class ProjectileDefinition(objectId : Int) extends ObjectDefinition(objectId)
private var useDamage1Subtract : Boolean = false private var useDamage1Subtract : Boolean = false
private var existsOnRemoteClients : Boolean = false //`true` spawns a server-managed object private var existsOnRemoteClients : Boolean = false //`true` spawns a server-managed object
private var remoteClientData : (Int, Int) = (0, 0) //artificial values; for ObjectCreateMessage packet (oicw_little_buddy is undefined) private var remoteClientData : (Int, Int) = (0, 0) //artificial values; for ObjectCreateMessage packet (oicw_little_buddy is undefined)
private var autoLock : Boolean = false
//derived calculations //derived calculations
private var distanceMax : Float = 0f private var distanceMax : Float = 0f
private var distanceFromAcceleration : Float = 0f private var distanceFromAcceleration : Float = 0f
@ -125,6 +126,13 @@ class ProjectileDefinition(objectId : Int) extends ObjectDefinition(objectId)
RemoteClientData RemoteClientData
} }
def AutoLock : Boolean = autoLock
def AutoLock_=(lockState : Boolean) : Boolean = {
autoLock = lockState
AutoLock
}
def DistanceMax : Float = distanceMax //accessor only def DistanceMax : Float = distanceMax //accessor only
def DistanceFromAcceleration : Float = distanceFromAcceleration //accessor only def DistanceFromAcceleration : Float = distanceFromAcceleration //accessor only

View file

@ -22,17 +22,15 @@ import shapeless.{::, HNil}
* This packet will continue to be dispatched by the client for as long as the projectile being tracked is in the air. * 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. * 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. * 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.
* <br> * <br>
* This control can not be exerted until that projectile is physically constructed on the other clients * This control can not be demonstrated until that projectile is physically constructed on the other clients
* in the same way that a player or a vehicle is constructed. * 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`. * A projectile that exhibits intentional construction behavior is flagged using the property `exists_on_remote_client`.
* The model comes with a number of caveats, * The model comes with a number of caveats,
* some that originate from the object construction process itself, * some that originate from the object construction process itself,
* but also some from this packet. * but also some from this packet.
* For example, * For example,
* as indicated by the static `shot_orient` values reported by this packet. * as indicated by the static `shot_original_orient` values reported by this packet.
* a discharged controlled projectile will not normally rotate. * a discharged controlled projectile will not normally rotate.
* A minor loss of lifespan may be levied. * A minor loss of lifespan may be levied.
* @see `ProjectileDefinition` * @see `ProjectileDefinition`
@ -41,18 +39,19 @@ import shapeless.{::, HNil}
* when dispatched by the server, the global unique identifier for the synchronized projectile object * when dispatched by the server, the global unique identifier for the synchronized projectile object
* @param shot_pos the position of the projectile * @param shot_pos the position of the projectile
* @param shot_vel the velocity of the projectile * @param shot_vel the velocity of the projectile
* @param shot_orient the orientation of the projectile * @param shot_original_orient the orientation of the projectile when it was discharged
* @param unk na; * @param sequence_num an incrementing index of the packet in this projectile's lifetime;
* usually `false` * suggests the "time alive" and indicates a place in packet ordering
* @param progress a measure of how long the projectile has been in the air; * @param explode indicates the projectile should explode
* often expressed in multiples of 2 * @param unk na
*/ */
final case class ProjectileStateMessage(projectile_guid : PlanetSideGUID, final case class ProjectileStateMessage(projectile_guid : PlanetSideGUID,
shot_pos : Vector3, shot_pos : Vector3,
shot_vel : Vector3, shot_vel : Vector3,
shot_orient : Vector3, shot_original_orient : Vector3,
unk : Boolean, sequence_num : Int,
progress : Int) explode : Boolean,
unk : Int)
extends PlanetSideGamePacket { extends PlanetSideGamePacket {
type Packet = ProjectileStateMessage type Packet = ProjectileStateMessage
def opcode = GamePacketOpcode.ProjectileStateMessage def opcode = GamePacketOpcode.ProjectileStateMessage
@ -67,16 +66,17 @@ object ProjectileStateMessage extends Marshallable[ProjectileStateMessage] {
("roll" | Angular.codec_roll) :: ("roll" | Angular.codec_roll) ::
("pitch" | Angular.codec_pitch) :: ("pitch" | Angular.codec_pitch) ::
("yaw" | Angular.codec_yaw()) :: ("yaw" | Angular.codec_yaw()) ::
("unk" | bool) :: ("sequence_num" | uint8) ::
("progress" | uint16L) ("explode" | bool) ::
("unk" | uint16L)
).xmap[ProjectileStateMessage] ( ).xmap[ProjectileStateMessage] (
{ {
case guid :: pos :: vel :: roll :: pitch :: yaw :: unk :: progress :: HNil => case guid :: pos :: vel :: roll :: pitch :: yaw :: sequence_num :: explode :: unk :: HNil =>
ProjectileStateMessage(guid, pos, vel, Vector3(roll, pitch, yaw), unk, progress) ProjectileStateMessage(guid, pos, vel, Vector3(roll, pitch, yaw), sequence_num , explode, unk)
}, },
{ {
case ProjectileStateMessage(guid, pos, vel, Vector3(roll, pitch, yaw), unk, progress) => case ProjectileStateMessage(guid, pos, vel, Vector3(roll, pitch, yaw), sequence_num, explode, unk) =>
guid :: pos :: vel :: roll :: pitch :: yaw :: unk :: progress :: HNil guid :: pos :: vel :: roll :: pitch :: yaw :: sequence_num :: explode :: unk :: HNil
} }
) )
} }

View file

@ -2,7 +2,7 @@
package services.avatar package services.avatar
import akka.actor.{Actor, ActorRef, Props} import akka.actor.{Actor, ActorRef, Props}
import net.psforever.packet.game.ObjectCreateMessage import net.psforever.packet.game.{ObjectCreateMessage, PlanetSideGUID}
import net.psforever.packet.game.objectcreate.{DroppedItemData, ObjectCreateMessageParent, PlacementData} import net.psforever.packet.game.objectcreate.{DroppedItemData, ObjectCreateMessageParent, PlacementData}
import services.avatar.support.{CorpseRemovalActor, DroppedItemRemover} import services.avatar.support.{CorpseRemovalActor, DroppedItemRemover}
import services.{GenericEventBus, RemoverActor, Service} import services.{GenericEventBus, RemoverActor, Service}
@ -161,13 +161,21 @@ class AvatarService extends Actor {
AvatarEvents.publish( 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)) 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.ProjectileAutoLockAwareness(mode) =>
AvatarEvents.publish(
AvatarServiceResponse(s"/$forChannel/Avatar", PlanetSideGUID(0), AvatarResponse.ProjectileAutoLockAwareness(mode))
)
case AvatarAction.ProjectileTrackingAwareness(guid) =>
AvatarEvents.publish(
AvatarServiceResponse(s"/$forChannel/Avatar", PlanetSideGUID(0), AvatarResponse.ProjectileTrackingAwareness(guid))
)
case AvatarAction.ProjectileExplodes(player_guid, projectile_guid, projectile) => case AvatarAction.ProjectileExplodes(player_guid, projectile_guid, projectile) =>
AvatarEvents.publish( AvatarEvents.publish(
AvatarServiceResponse(s"/$forChannel/Avatar", player_guid, AvatarResponse.ProjectileExplodes(projectile_guid, projectile)) AvatarServiceResponse(s"/$forChannel/Avatar", player_guid, AvatarResponse.ProjectileExplodes(projectile_guid, projectile))
) )
case AvatarAction.ProjectileState(player_guid, projectile_guid, shot_pos, shot_vel, shot_orient, unk, time_alive) => case AvatarAction.ProjectileState(player_guid, projectile_guid, shot_pos, shot_vel, shot_orient, unk1, unk2, unk3) =>
AvatarEvents.publish( AvatarEvents.publish(
AvatarServiceResponse(s"/$forChannel/Avatar", player_guid, AvatarResponse.ProjectileState(projectile_guid, shot_pos, shot_vel, shot_orient, unk, time_alive)) AvatarServiceResponse(s"/$forChannel/Avatar", player_guid, AvatarResponse.ProjectileState(projectile_guid, shot_pos, shot_vel, shot_orient, unk1, unk2, unk3))
) )
case AvatarAction.PickupItem(player_guid, zone, target, slot, item, unk) => case AvatarAction.PickupItem(player_guid, zone, target, slot, item, unk) =>
janitor forward RemoverActor.ClearSpecific(List(item), zone) janitor forward RemoverActor.ClearSpecific(List(item), zone)

View file

@ -49,8 +49,10 @@ object AvatarAction {
final case class PlanetsideAttributeSelf(player_guid : PlanetSideGUID, attribute_type : Int, attribute_value : Long) extends Action 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 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 PickupItem(player_guid : PlanetSideGUID, zone : Zone, target : PlanetSideGameObject with Container, slot : Int, item : Equipment, unk : Int = 0) extends Action
final case class ProjectileAutoLockAwareness(mode : Int) extends Action
final case class ProjectileTrackingAwareness(projectile_guid : PlanetSideGUID) extends Action
final case class ProjectileExplodes(player_guid : PlanetSideGUID, projectile_guid : PlanetSideGUID, projectile : Projectile) extends Action final case class ProjectileExplodes(player_guid : PlanetSideGUID, projectile_guid : PlanetSideGUID, projectile : Projectile) 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 ProjectileState(player_guid : PlanetSideGUID, projectile_guid : PlanetSideGUID, shot_pos : Vector3, shot_vel : Vector3, shot_orient : Vector3, unk1 : Int, unk2 : Boolean, unk3 : Int) extends Action
final case class PutDownFDU(player_guid : PlanetSideGUID) 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 Release(player : Player, zone : Zone, time : Option[FiniteDuration] = None) extends Action
final case class Revive(target_guid: PlanetSideGUID) extends Action final case class Revive(target_guid: PlanetSideGUID) extends Action

View file

@ -41,8 +41,10 @@ object AvatarResponse {
final case class PlanetsideAttributeToAll(attribute_type : Int, attribute_value : Long) extends Response 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 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(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 ProjectileAutoLockAwareness(mode : Int) extends Response
final case class ProjectileTrackingAwareness(projectile_guid : PlanetSideGUID) extends Response
final case class ProjectileExplodes(projectile_guid : PlanetSideGUID, projectile : Projectile) extends Response final case class ProjectileExplodes(projectile_guid : PlanetSideGUID, projectile : Projectile) 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 final case class ProjectileState(projectile_guid : PlanetSideGUID, shot_pos : Vector3, shot_vel : Vector3, shot_orient : Vector3, unk1 : Int, unk2 : Boolean, unk3 : Int) extends Response
final case class PutDownFDU(target_guid : PlanetSideGUID) extends Response final case class PutDownFDU(target_guid : PlanetSideGUID) extends Response
final case class Release(player : Player) extends Response final case class Release(player : Player) extends Response
final case class Reload(weapon_guid : PlanetSideGUID) extends Response final case class Reload(weapon_guid : PlanetSideGUID) extends Response

View file

@ -8,17 +8,18 @@ import net.psforever.types.Vector3
import scodec.bits._ import scodec.bits._
class ProjectileStateMessageTest extends Specification { class ProjectileStateMessageTest extends Specification {
val string = hex"3f 259d c5019 30e4a 9514 c52c9541 d9ba05c2 c5973941 00 f8 ec 020000" val string = hex"3f 259d c5019 30e4a 9514 c52c9541 d9ba05c2 c5973941 00 f8 ec 02000000"
"decode" in { "decode" in {
PacketCoding.DecodePacket(string).require match { PacketCoding.DecodePacket(string).require match {
case ProjectileStateMessage(projectile, pos, vel, orient, unk, time_alive) => case ProjectileStateMessage(projectile, pos, vel, orient, sequence, explode, unk) =>
projectile mustEqual PlanetSideGUID(40229) projectile mustEqual PlanetSideGUID(40229)
pos mustEqual Vector3(4611.539f, 5576.375f, 82.328125f) pos mustEqual Vector3(4611.539f, 5576.375f, 82.328125f)
vel mustEqual Vector3(18.64686f, -33.43247f, 11.599553f) vel mustEqual Vector3(18.64686f, -33.43247f, 11.599553f)
orient mustEqual Vector3(0, 22.5f, 56.25f) orient mustEqual Vector3(0, 22.5f, 146.25f)
unk mustEqual false sequence mustEqual 2
time_alive mustEqual 4 explode mustEqual false
unk mustEqual 0
case _ => case _ =>
ko ko
} }
@ -29,9 +30,10 @@ class ProjectileStateMessageTest extends Specification {
PlanetSideGUID(40229), PlanetSideGUID(40229),
Vector3(4611.539f, 5576.375f, 82.328125f), Vector3(4611.539f, 5576.375f, 82.328125f),
Vector3(18.64686f, -33.43247f, 11.599553f), Vector3(18.64686f, -33.43247f, 11.599553f),
Vector3(0, 22.5f, 56.25f), Vector3(0, 22.5f, 146.25f),
2,
false, false,
4 0
) )
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector val pkt = PacketCoding.EncodePacket(msg).require.toByteVector

View file

@ -153,6 +153,9 @@ class WorldSessionActor extends Actor with MDCContextAware {
lazy val unsignedIntMaxValue : Long = Int.MaxValue.toLong * 2L + 1L lazy val unsignedIntMaxValue : Long = Int.MaxValue.toLong * 2L + 1L
var serverTime : Long = 0 var serverTime : Long = 0
var projectileAutoLockTargets : List[PlanetSideGUID] = Nil
var projectileAutoLocksActive : Set[PlanetSideGUID] = Set.empty
var amsSpawnPoints : List[SpawnPoint] = Nil var amsSpawnPoints : List[SpawnPoint] = Nil
var clientKeepAlive : Cancellable = DefaultCancellable.obj var clientKeepAlive : Cancellable = DefaultCancellable.obj
var progressBarUpdate : Cancellable = DefaultCancellable.obj var progressBarUpdate : Cancellable = DefaultCancellable.obj
@ -1473,31 +1476,42 @@ class WorldSessionActor extends Actor with MDCContextAware {
} }
} }
case AvatarResponse.ProjectileTrackingAwareness(projectile_guid) =>
continent.GUID(projectile_guid) match {
case Some(projectile : Projectile) =>
val mode = 7 + (projectile.profile == GlobalDefinitions.wasp_rocket_projectile)
sendResponse(GenericActionMessage(mode))
case _ => ;
}
case AvatarResponse.ProjectileExplodes(projectile_guid, projectile) => case AvatarResponse.ProjectileExplodes(projectile_guid, projectile) =>
//turn the projectile into a boomer // //turn the projectile into a boomer
sendResponse( // sendResponse(
ObjectCreateMessage( // ObjectCreateMessage(
GlobalDefinitions.boomer.ObjectId, // GlobalDefinitions.boomer.ObjectId,
projectile_guid, // projectile_guid,
CommonFieldDataWithPlacement( // CommonFieldDataWithPlacement(
PlacementData(projectile.Position, projectile.Orientation), // PlacementData(projectile.Position, projectile.Orientation),
CommonFieldData(projectile.owner.Faction,false,false,false,None,false,Some(false),None, PlanetSideGUID(0)) // CommonFieldData(projectile.owner.Faction,false,false,false,None,false,Some(false),None, PlanetSideGUID(0))
) // )
) // )
) // )
//detonate the boomer, then clean it up // //detonate the boomer, then clean it up
sendResponse(TriggerEffectMessage(projectile_guid, "detonate_boomer")) // sendResponse(TriggerEffectMessage(projectile_guid, "detonate_boomer"))
sendResponse(ObjectDeleteMessage(projectile_guid, 2)) sendResponse(ObjectDeleteMessage(projectile_guid, 2))
case AvatarResponse.ProjectileState(projectile_guid, shot_pos, shot_vel, shot_orient, unk, time_alive) => case AvatarResponse.ProjectileAutoLockAwareness(mode) =>
sendResponse(GenericActionMessage(mode))
case AvatarResponse.ProjectileState(projectile_guid, shot_pos, shot_vel, shot_orient, unk1, unk2, unk3) =>
if(tplayer_guid != guid) { if(tplayer_guid != guid) {
//sendResponse(ProjectileStateMessage(projectile_guid, shot_pos, shot_vel, shot_orient, unk, time_alive)) sendResponse(ProjectileStateMessage(projectile_guid, shot_pos, shot_vel, shot_orient, unk1, unk2, unk3))
continent.GUID(projectile_guid) match { // continent.GUID(projectile_guid) match {
case Some(obj) => // case Some(obj) =>
val definition = obj.Definition // val definition = obj.Definition
sendResponse(ObjectCreateMessage(definition.ObjectId, projectile_guid, definition.Packet.ConstructorData(obj).get)) // sendResponse(ObjectCreateMessage(definition.ObjectId, projectile_guid, definition.Packet.ConstructorData(obj).get))
case _ => ; // case _ => ;
} // }
} }
case AvatarResponse.PutDownFDU(target) => case AvatarResponse.PutDownFDU(target) =>
@ -3481,7 +3495,10 @@ class WorldSessionActor extends Actor with MDCContextAware {
import net.psforever.objects.GlobalDefinitions._ import net.psforever.objects.GlobalDefinitions._
import net.psforever.types.CertificationType._ import net.psforever.types.CertificationType._
val faction = PlanetSideEmpire.VS val faction =
if(sessionId % 5 == 0) PlanetSideEmpire.TR
else if(sessionId % 3 == 0) PlanetSideEmpire.NC
else PlanetSideEmpire.VS
val avatar = new Avatar(41605313L+sessionId, s"TestCharacter$sessionId", faction, CharacterGender.Female, 41, CharacterVoice.Voice1) val avatar = new Avatar(41605313L+sessionId, s"TestCharacter$sessionId", faction, CharacterGender.Female, 41, CharacterVoice.Voice1)
avatar.Certifications += StandardAssault avatar.Certifications += StandardAssault
avatar.Certifications += MediumAssault avatar.Certifications += MediumAssault
@ -3539,7 +3556,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
//player.Slot(12).Equipment = AmmoBox(bullet_9mm) //player.Slot(12).Equipment = AmmoBox(bullet_9mm)
//player.Slot(33).Equipment = AmmoBox(bullet_9mm_AP) //player.Slot(33).Equipment = AmmoBox(bullet_9mm_AP)
//player.Slot(36).Equipment = AmmoBox(GlobalDefinitions.StandardPistolAmmo(player.Faction)) //player.Slot(36).Equipment = AmmoBox(GlobalDefinitions.StandardPistolAmmo(player.Faction))
//player.Slot(39).Equipment = SimpleItem(remote_electronics_kit) player.Slot(39).Equipment = SimpleItem(remote_electronics_kit)
player.Locker.Inventory += 0 -> SimpleItem(remote_electronics_kit) player.Locker.Inventory += 0 -> SimpleItem(remote_electronics_kit)
player.Inventory.Items.foreach { _.obj.Faction = faction } player.Inventory.Items.foreach { _.obj.Faction = faction }
//TODO end temp player character auto-loading //TODO end temp player character auto-loading
@ -4031,15 +4048,15 @@ class WorldSessionActor extends Actor with MDCContextAware {
case msg @ VehicleSubStateMessage(vehicle_guid, player_guid, vehicle_pos, vehicle_ang, vel, unk1, unk2) => case msg @ VehicleSubStateMessage(vehicle_guid, player_guid, vehicle_pos, vehicle_ang, vel, unk1, unk2) =>
//log.info(s"VehicleSubState: $vehicle_guid, $player_guid, $vehicle_pos, $vehicle_ang, $vel, $unk1, $unk2") //log.info(s"VehicleSubState: $vehicle_guid, $player_guid, $vehicle_pos, $vehicle_ang, $vel, $unk1, $unk2")
case msg @ ProjectileStateMessage(projectile_guid, shot_pos, shot_vel, shot_orient, unk, progress) => case msg @ ProjectileStateMessage(projectile_guid, shot_pos, shot_vel, shot_orient, unk1, unk2, unk3) =>
//log.info(s"ProjectileState: $msg") log.info(s"ProjectileState: $msg")
projectiles(projectile_guid.guid - Projectile.BaseUID) match { projectiles(projectile_guid.guid - Projectile.BaseUID) match {
case Some(projectile) if projectile.HasGUID => case Some(projectile) if projectile.HasGUID =>
val projectileGlobalUID = projectile.GUID val projectileGlobalUID = projectile.GUID
projectile.Position = shot_pos projectile.Position = shot_pos
projectile.Orientation = shot_orient projectile.Orientation = shot_orient
projectile.Velocity = shot_vel projectile.Velocity = shot_vel
avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.ProjectileState(player.GUID, projectileGlobalUID, shot_pos, shot_vel, shot_orient, unk, progress)) avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.ProjectileState(player.GUID, projectileGlobalUID, shot_pos, shot_vel, shot_orient, unk1, unk2, unk3))
case _ => case _ =>
log.error(s"ProjectileState: the projectile@${projectile_guid.guid} can not be found") log.error(s"ProjectileState: the projectile@${projectile_guid.guid} can not be found")
} }
@ -5496,6 +5513,32 @@ class WorldSessionActor extends Actor with MDCContextAware {
case msg @ WeaponLazeTargetPositionMessage(weapon, pos1, pos2) => case msg @ WeaponLazeTargetPositionMessage(weapon, pos1, pos2) =>
log.info("Lazing position: " + pos2.toString) log.info("Lazing position: " + pos2.toString)
case msg @ ObjectDetectedMessage(guid1, guid2, unk, targets) =>
FindWeapon match {
case Some(weapon) if weapon.Projectile.AutoLock =>
//projectile with auto-lock instigates a warning on the target
val mode = 7 + (weapon.Projectile == GlobalDefinitions.wasp_rocket_projectile)
projectileAutoLockTargets = targets
targets
.map { continent.GUID }
.collect {
case Some(obj : Vehicle) if !obj.Cloaked =>
//TODO vehicleService ! VehicleServiceMessage(s"${obj.Actor}", VehicleAction.ProjectileAutoLockAwareness(mode))
obj.Seats.values
.collect { case seat if seat.isOccupied =>
avatarService ! AvatarServiceMessage(s"${seat.Occupant.get.Name}", AvatarAction.ProjectileAutoLockAwareness(mode))
}
case Some(obj : Mountable) =>
obj.Seats.values
.collect { case seat if seat.isOccupied =>
avatarService ! AvatarServiceMessage(s"${seat.Occupant.get.Name}", AvatarAction.ProjectileAutoLockAwareness(mode))
}
case Some(obj : Player) if obj.ExoSuit == ExoSuitType.MAX =>
avatarService ! AvatarServiceMessage(s"${obj.Name}", AvatarAction.ProjectileAutoLockAwareness(mode))
}
case _ => ;
}
case msg @ HitMessage(seq_time, projectile_guid, unk1, hit_info, unk2, unk3, unk4) => case msg @ HitMessage(seq_time, projectile_guid, unk1, hit_info, unk2, unk3, unk4) =>
log.info(s"Hit: $msg") log.info(s"Hit: $msg")
(hit_info match { (hit_info match {
@ -5544,7 +5587,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
}) })
if(projectile.profile.ExistsOnRemoteClients) { if(projectile.profile.ExistsOnRemoteClients) {
//cleanup //cleanup
avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.ProjectileExplodes(player.GUID, projectile_guid, projectile)) avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.ProjectileExplodes(player.GUID, projectile.GUID, projectile))
taskResolver ! UnregisterProjectile(projectile) taskResolver ! UnregisterProjectile(projectile)
} }
case None => ; case None => ;