'don't knock it if it works' controlled projectiles

This commit is contained in:
FateJH 2019-11-01 11:11:47 -04:00
parent 8952ab86f6
commit d1ba353cad
9 changed files with 63 additions and 120 deletions

View file

@ -54,7 +54,7 @@ lazy val psloginPackSettings = packAutoSettings ++ Seq(
lazy val root = (project in file(".")).
settings(commonSettings: _*).
enablePlugins(ScalaUnidocPlugin).
//enablePlugins(ScalaUnidocPlugin).
settings(psloginPackSettings: _*).
aggregate(pslogin, common)

View file

@ -31,70 +31,18 @@ object GlobalDefinitions {
*/
val avatar = new AvatarDefinition(121)
/*
Exo-suits
exo-suits
*/
val Standard = ExoSuitDefinition(ExoSuitType.Standard)
Standard.Name = "standard"
Standard.MaxArmor = 50
Standard.InventoryScale = InventoryTile.Tile96
Standard.InventoryOffset = 6
Standard.Holster(0, EquipmentSize.Pistol)
Standard.Holster(2, EquipmentSize.Rifle)
Standard.Holster(4, EquipmentSize.Melee)
Standard.ResistanceDirectHit = 4
Standard.ResistanceSplash = 15
Standard.ResistanceAggravated = 8
val Agile = ExoSuitDefinition(ExoSuitType.Agile)
Agile.Name = "agile"
Agile.MaxArmor = 100
Agile.InventoryScale = InventoryTile.Tile99
Agile.InventoryOffset = 6
Agile.Holster(0, EquipmentSize.Pistol)
Agile.Holster(1, EquipmentSize.Pistol)
Agile.Holster(2, EquipmentSize.Rifle)
Agile.Holster(4, EquipmentSize.Melee)
Agile.ResistanceDirectHit = 6
Agile.ResistanceSplash = 25
Agile.ResistanceAggravated = 10
val Reinforced = ExoSuitDefinition(ExoSuitType.Reinforced)
Reinforced.Name = "reinforced"
Reinforced.Permissions = List(CertificationType.ReinforcedExoSuit)
Reinforced.MaxArmor = 200
Reinforced.InventoryScale = InventoryTile.Tile1209
Reinforced.InventoryOffset = 6
Reinforced.Holster(0, EquipmentSize.Pistol)
Reinforced.Holster(1, EquipmentSize.Pistol)
Reinforced.Holster(2, EquipmentSize.Rifle)
Reinforced.Holster(3, EquipmentSize.Rifle)
Reinforced.Holster(4, EquipmentSize.Melee)
Reinforced.ResistanceDirectHit = 10
Reinforced.ResistanceSplash = 35
Reinforced.ResistanceAggravated = 12
val Infiltration = ExoSuitDefinition(ExoSuitType.Infiltration)
Infiltration.Name = "infiltration_suit"
Infiltration.Permissions = List(CertificationType.InfiltrationSuit)
Infiltration.MaxArmor = 0
Infiltration.InventoryScale = InventoryTile.Tile66
Infiltration.InventoryOffset = 6
Infiltration.Holster(0, EquipmentSize.Pistol)
Infiltration.Holster(4, EquipmentSize.Melee)
val MAX = SpecialExoSuitDefinition(ExoSuitType.MAX)
MAX.Permissions = List(CertificationType.AIMAX,CertificationType.AVMAX, CertificationType.AAMAX, CertificationType.UniMAX)
MAX.MaxArmor = 650
MAX.InventoryScale = InventoryTile.Tile1612
MAX.InventoryOffset = 6
MAX.Holster(0, EquipmentSize.Max)
MAX.Holster(4, EquipmentSize.Melee)
MAX.Subtract.Damage1 = -2
MAX.ResistanceDirectHit = 6
MAX.ResistanceSplash = 35
MAX.ResistanceAggravated = 10
MAX.Damage = StandardMaxDamage
MAX.Model = StandardResolutions.Max
init_exosuit()
/*
Implants
*/
@ -632,15 +580,9 @@ object GlobalDefinitions {
val phoenix = ToolDefinition(ObjectClass.phoenix) //decimator
val striker = new ToolDefinition(ObjectClass.striker) {
override def NextFireModeIndex(index : Int) : Int = index
DefaultFireModeIndex = 1
}
val striker = ToolDefinition(ObjectClass.striker)
val hunterseeker = new ToolDefinition(ObjectClass.hunterseeker) {
override def NextFireModeIndex(index : Int) : Int = index
DefaultFireModeIndex = 1
} //phoenix
val hunterseeker = ToolDefinition(ObjectClass.hunterseeker)
val lancer = ToolDefinition(ObjectClass.lancer)
@ -807,9 +749,7 @@ object GlobalDefinitions {
val lightgunship_weapon_system = ToolDefinition(ObjectClass.lightgunship_weapon_system)
val wasp_weapon_system = new ToolDefinition(ObjectClass.wasp_weapon_system) {
override def NextFireModeIndex(index : Int) : Int = index
}
val wasp_weapon_system = new ToolDefinition(ObjectClass.wasp_weapon_system)
val liberator_weapon_system = ToolDefinition(ObjectClass.liberator_weapon_system)
@ -955,13 +895,13 @@ object GlobalDefinitions {
val router_telepad_deployable = DeployableDefinition(DeployedItem.router_telepad_deployable)
//this is only treated like a deployable
val internal_router_telepad_deployable = DeployableDefinition(DeployedItem.router_telepad_deployable)
init_deployables()
/*
Miscellaneous
*/
val ams_respawn_tube = new SpawnTubeDefinition(49)
val matrix_terminala = new MatrixTerminalDefinition(517)

View file

@ -15,7 +15,7 @@ class ProjectileConverter extends ObjectCreateConverter[Projectile]() {
PlacementData(
obj.Position,
obj.Orientation,
None
obj.Velocity
),
CommonFieldData(
obj.owner.Faction,

View file

@ -37,22 +37,22 @@ import shapeless.{::, HNil}
* 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 projectile_guid when dispatched by the client, the client-specific local unique identifier of the projectile;
* when dispatched by the server, 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 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
* @param progress a measure of 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,
shot_orient : Vector3,
unk : Boolean,
time_alive : Int)
progress : Int)
extends PlanetSideGamePacket {
type Packet = ProjectileStateMessage
def opcode = GamePacketOpcode.ProjectileStateMessage
@ -68,15 +68,15 @@ object ProjectileStateMessage extends Marshallable[ProjectileStateMessage] {
("pitch" | Angular.codec_pitch) ::
("yaw" | Angular.codec_yaw()) ::
("unk" | bool) ::
("time_alive" | uint16L)
("progress" | uint16L)
).xmap[ProjectileStateMessage] (
{
case guid :: pos :: vel :: roll :: pitch :: yaw :: unk :: time :: HNil =>
ProjectileStateMessage(guid, pos, vel, Vector3(roll, pitch, yaw), unk, time)
case guid :: pos :: vel :: roll :: pitch :: yaw :: unk :: progress :: HNil =>
ProjectileStateMessage(guid, pos, vel, Vector3(roll, pitch, yaw), unk, progress)
},
{
case ProjectileStateMessage(guid, pos, vel, Vector3(roll, pitch, yaw), unk, time) =>
guid :: pos :: vel :: roll :: pitch :: yaw :: unk :: time :: HNil
case ProjectileStateMessage(guid, pos, vel, Vector3(roll, pitch, yaw), unk, progress) =>
guid :: pos :: vel :: roll :: pitch :: yaw :: unk :: progress :: HNil
}
)
}

View file

@ -161,6 +161,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.ProjectileExplodes(player_guid, projectile_guid, projectile) =>
AvatarEvents.publish(
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) =>
AvatarEvents.publish(
AvatarServiceResponse(s"/$forChannel/Avatar", player_guid, AvatarResponse.ProjectileState(projectile_guid, shot_pos, shot_vel, shot_orient, unk, time_alive))

View file

@ -1,12 +1,8 @@
// 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
@ -53,6 +49,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 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 PutDownFDU(player_guid : PlanetSideGUID) extends Action
final case class Release(player : Player, zone : Zone, time : Option[FiniteDuration] = None) extends Action

View file

@ -2,7 +2,7 @@
package services.avatar
import net.psforever.objects.Player
import net.psforever.objects.ballistics.SourceEntry
import net.psforever.objects.ballistics.{Projectile, SourceEntry}
import net.psforever.objects.equipment.Equipment
import net.psforever.packet.PlanetSideGamePacket
import net.psforever.packet.game.objectcreate.ConstructorData
@ -38,14 +38,11 @@ object AvatarResponse {
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 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
>>>>>>> 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

@ -3,4 +3,4 @@ logLevel := Level.Warn
addSbtPlugin("org.xerial.sbt" % "sbt-pack" % "0.7.9")
addSbtPlugin("org.scoverage" % "sbt-scoverage" % "1.3.5")
// https://github.com/sbt/sbt-unidoc
addSbtPlugin("com.eed3si9n" % "sbt-unidoc" % "0.4.2")
//addSbtPlugin("com.eed3si9n" % "sbt-unidoc" % "0.4.2")

View file

@ -1473,9 +1473,31 @@ class WorldSessionActor extends Actor with MDCContextAware {
}
}
case AvatarResponse.ProjectileExplodes(projectile_guid, projectile) =>
//turn the projectile into a boomer
sendResponse(
ObjectCreateMessage(
GlobalDefinitions.boomer.ObjectId,
projectile_guid,
CommonFieldDataWithPlacement(
PlacementData(projectile.Position, projectile.Orientation),
CommonFieldData(projectile.owner.Faction,false,false,false,None,false,Some(false),None, PlanetSideGUID(0))
)
)
)
//detonate the boomer, then clean it up
sendResponse(TriggerEffectMessage(projectile_guid, "detonate_boomer"))
sendResponse(ObjectDeleteMessage(projectile_guid, 2))
case AvatarResponse.ProjectileState(projectile_guid, shot_pos, shot_vel, shot_orient, unk, time_alive) =>
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, unk, time_alive))
continent.GUID(projectile_guid) match {
case Some(obj) =>
val definition = obj.Definition
sendResponse(ObjectCreateMessage(definition.ObjectId, projectile_guid, definition.Packet.ConstructorData(obj).get))
case _ => ;
}
}
case AvatarResponse.PutDownFDU(target) =>
@ -3509,14 +3531,15 @@ class WorldSessionActor extends Actor with MDCContextAware {
//player.Orientation = Vector3(0f, 0f, 132.1875f)
// player.ExoSuit = ExoSuitType.MAX //TODO strange issue; divide number above by 10 when uncommenting
player.Slot(0).Equipment = Tool(GlobalDefinitions.StandardPistol(player.Faction))
player.Slot(2).Equipment = Tool(suppressor)
player.Slot(2).Equipment = Tool(hunterseeker) //Tool(suppressor)
player.Slot(4).Equipment = Tool(GlobalDefinitions.StandardMelee(player.Faction))
player.Slot(6).Equipment = AmmoBox(bullet_9mm)
player.Slot(9).Equipment = AmmoBox(bullet_9mm)
player.Slot(12).Equipment = AmmoBox(bullet_9mm)
player.Slot(33).Equipment = AmmoBox(bullet_9mm_AP)
player.Slot(36).Equipment = AmmoBox(GlobalDefinitions.StandardPistolAmmo(player.Faction))
player.Slot(39).Equipment = SimpleItem(remote_electronics_kit)
player.Slot(6).Equipment = AmmoBox(hunter_seeker_missile, 65535)
//player.Slot(6).Equipment = AmmoBox(bullet_9mm)
//player.Slot(9).Equipment = AmmoBox(bullet_9mm)
//player.Slot(12).Equipment = AmmoBox(bullet_9mm)
//player.Slot(33).Equipment = AmmoBox(bullet_9mm_AP)
//player.Slot(36).Equipment = AmmoBox(GlobalDefinitions.StandardPistolAmmo(player.Faction))
//player.Slot(39).Equipment = SimpleItem(remote_electronics_kit)
player.Locker.Inventory += 0 -> SimpleItem(remote_electronics_kit)
player.Inventory.Items.foreach { _.obj.Faction = faction }
//TODO end temp player character auto-loading
@ -3900,25 +3923,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
}
if(!player.Crouching && is_crouching) {
sendResponse(
ObjectCreateMessage(
405,
PlanetSideGUID(40288),
TrackedProjectileData(
CommonFieldDataWithPlacement(
PlacementData(Vector3(3561.0f, 2854.0f, 92.859375f), Vector3(0f, 348.75f, 267.1875f), None),
CommonFieldData(PlanetSideEmpire.NC, false, false, true, None, false, None, None, PlanetSideGUID(0))
),
39577, 201, FlightPhysics.State4, 0, 0
)
)
)
}
else if(player.Crouching && !is_crouching) {
sendResponse(
ObjectDeleteMessage(PlanetSideGUID(40288), 2)
//ProjectileStateMessage(PlanetSideGUID(40288),Vector3(3561.0f, 2854.0f, 92.859375f),Vector3(-38.814934f,-2.578959f,-9.313708f),Vector3(0,348.75f,267.1875f),false,0)
)
//...
}
player.Position = pos
player.Velocity = vel
@ -4026,16 +4031,15 @@ class WorldSessionActor extends Actor with MDCContextAware {
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")
case msg @ ProjectileStateMessage(projectile_guid, shot_pos, shot_vel, shot_orient, unk, time_alive) =>
log.info(s"ProjectileState: $msg")
case msg @ ProjectileStateMessage(projectile_guid, shot_pos, shot_vel, shot_orient, unk, progress) =>
//log.info(s"ProjectileState: $msg")
projectiles(projectile_guid.guid - Projectile.BaseUID) match {
case Some(projectile) if projectile.HasGUID =>
val projectileGlobalUID = projectile.GUID
log.info(s"ProjectileState: mapped local uid ${projectile_guid.guid} to global uid ${projectileGlobalUID.guid}; updating object ...")
projectile.Position = shot_pos
projectile.Orientation = shot_orient
projectile.Velocity = shot_vel
avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.ProjectileState(player.GUID, projectile.GUID, shot_pos, shot_vel, shot_orient, unk, time_alive))
avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.ProjectileState(player.GUID, projectileGlobalUID, shot_pos, shot_vel, shot_orient, unk, progress))
case _ =>
log.error(s"ProjectileState: the projectile@${projectile_guid.guid} can not be found")
}
@ -5540,6 +5544,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
})
if(projectile.profile.ExistsOnRemoteClients) {
//cleanup
avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.ProjectileExplodes(player.GUID, projectile_guid, projectile))
taskResolver ! UnregisterProjectile(projectile)
}
case None => ;
@ -8108,7 +8113,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
}
/**
* If the corpse has been well-looted, it has no items in its primary holsters nor any items in its inventory.
* If the corpse has been well-lootedP, it has no items in its primary holsters nor any items in its inventory.
* @param obj the corpse
* @return `true`, if the `obj` is actually a corpse and has no objects in its holsters or backpack;
* `false`, otherwise