mirror of
https://github.com/2revoemag/PSF-BotServer.git
synced 2026-02-12 19:31:04 +00:00
basic projectiles tracked in WSA - generated (WeaponFire), queued, and marked as resolved through any of four packets (RequestDestroy, Hit, Splash, and Lash)
This commit is contained in:
parent
1bceb35226
commit
c57999d676
11 changed files with 115 additions and 15 deletions
|
|
@ -14,6 +14,7 @@ import net.psforever.objects.serverobject.pad.VehicleSpawnPadDefinition
|
|||
import net.psforever.objects.serverobject.terminals._
|
||||
import net.psforever.objects.serverobject.tube.SpawnTubeDefinition
|
||||
import net.psforever.objects.serverobject.resourcesilo.ResourceSiloDefinition
|
||||
import net.psforever.objects.ballistics.{DamageType, Projectiles}
|
||||
import net.psforever.objects.vehicles.{SeatArmorRestriction, UtilityType}
|
||||
import net.psforever.types.PlanetSideEmpire
|
||||
|
||||
|
|
|
|||
42
common/src/main/scala/net/psforever/objects/Projectile.scala
Normal file
42
common/src/main/scala/net/psforever/objects/Projectile.scala
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package net.psforever.objects
|
||||
|
||||
import net.psforever.objects.definition.{ProjectileDefinition, ToolDefinition}
|
||||
import net.psforever.objects.entity.SimpleWorldEntity
|
||||
import net.psforever.objects.ballistics.ProjectileResolution
|
||||
import net.psforever.types.Vector3
|
||||
|
||||
final case class Projectile(profile : ProjectileDefinition,
|
||||
tool_def : ToolDefinition,
|
||||
pos : Vector3,
|
||||
orient : Vector3,
|
||||
resolution : ProjectileResolution.Value,
|
||||
fire_time : Long = System.nanoTime,
|
||||
hit_time : Long = 0) {
|
||||
val current : SimpleWorldEntity = new SimpleWorldEntity()
|
||||
|
||||
def Resolve(hitPos : Vector3, hitAng : Vector3, hitVel : Vector3, resolution : ProjectileResolution.Value) : Projectile = {
|
||||
val obj = Resolve(resolution)
|
||||
obj.current.Position = hitPos
|
||||
obj.current.Orientation = hitAng
|
||||
obj.current.Velocity = hitVel
|
||||
obj
|
||||
}
|
||||
|
||||
def Resolve(resolution : ProjectileResolution.Value) : Projectile = {
|
||||
resolution match {
|
||||
case ProjectileResolution.Unresolved =>
|
||||
this
|
||||
case _ =>
|
||||
Projectile(profile, tool_def, pos, orient, resolution, fire_time, System.nanoTime)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
object Projectile {
|
||||
final val BaseUID : Int = 40100
|
||||
|
||||
def apply(profile : ProjectileDefinition, tool_def : ToolDefinition, pos : Vector3, orient : Vector3) : Projectile = {
|
||||
Projectile(profile, tool_def, pos, orient, ProjectileResolution.Unresolved)
|
||||
}
|
||||
}
|
||||
|
|
@ -3,6 +3,7 @@ package net.psforever.objects
|
|||
|
||||
import net.psforever.objects.definition.{AmmoBoxDefinition, ProjectileDefinition, ToolDefinition}
|
||||
import net.psforever.objects.equipment._
|
||||
import net.psforever.objects.ballistics.Projectiles
|
||||
|
||||
import scala.annotation.tailrec
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package net.psforever.objects.equipment
|
||||
package net.psforever.objects.ballistics
|
||||
|
||||
trait DamageProfile {
|
||||
def Damage0 : Int
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package net.psforever.objects.equipment
|
||||
package net.psforever.objects.ballistics
|
||||
|
||||
/**
|
||||
* An `Enumeration` of the damage type.
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package net.psforever.objects.ballistics
|
||||
|
||||
object ProjectileResolution extends Enumeration {
|
||||
type Type = Value
|
||||
|
||||
val
|
||||
Unresolved,
|
||||
MissedShot,
|
||||
Target,
|
||||
Obstacle
|
||||
= Value
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package net.psforever.objects.equipment
|
||||
package net.psforever.objects.ballistics
|
||||
|
||||
/**
|
||||
* An `Enumeration` of all the projectile types in the game, paired with their object id as the `Value`.
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package net.psforever.objects.definition
|
||||
|
||||
import net.psforever.objects.equipment.{DamageProfile, DamageType, Projectiles}
|
||||
import net.psforever.objects.ballistics.{DamageProfile, DamageType, Projectiles}
|
||||
|
||||
class ProjectileDefinition(objectId : Int) extends ObjectDefinition(objectId) with DamageProfile {
|
||||
private val projectileType : Projectiles.Value = Projectiles(objectId) //let throw NoSuchElementException
|
||||
|
|
|
|||
|
|
@ -4,8 +4,8 @@ package net.psforever.objects.entity
|
|||
import net.psforever.types.Vector3
|
||||
|
||||
class SimpleWorldEntity extends WorldEntity {
|
||||
private var coords : Vector3 = Vector3(0f, 0f, 0f)
|
||||
private var orient : Vector3 = Vector3(0f, 0f, 0f)
|
||||
private var coords : Vector3 = Vector3.Zero
|
||||
private var orient : Vector3 = Vector3.Zero
|
||||
private var vel : Option[Vector3] = None
|
||||
|
||||
def Position : Vector3 = coords
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
package net.psforever.objects.equipment
|
||||
|
||||
import net.psforever.objects.Tool
|
||||
import net.psforever.objects.ballistics.DamageProfile
|
||||
|
||||
import scala.collection.mutable
|
||||
|
||||
|
|
|
|||
|
|
@ -53,6 +53,7 @@ import scala.concurrent.Future
|
|||
import scala.concurrent.duration._
|
||||
import scala.util.Success
|
||||
import akka.pattern.ask
|
||||
import net.psforever.objects.ballistics.ProjectileResolution
|
||||
|
||||
class WorldSessionActor extends Actor with MDCContextAware {
|
||||
import WorldSessionActor._
|
||||
|
|
@ -84,6 +85,9 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
var traveler : Traveler = null
|
||||
var deadState : DeadState.Value = DeadState.Dead
|
||||
var whenUsedLastKit : Long = 0
|
||||
/** the client rotates between 40100 -- 40124 for projectiles normally, skipping only for long-lived projectiles
|
||||
* 40125 -- 40149 is being reserved as a (potential) guard against overflow */
|
||||
val projectiles : Array[Option[Projectile]] = Array.fill[Option[Projectile]](50)(None)
|
||||
|
||||
var amsSpawnPoint : Option[SpawnTube] = None
|
||||
|
||||
|
|
@ -2586,7 +2590,6 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
else if((player.DrawnSlot = held_holsters) != before) {
|
||||
avatarService ! AvatarServiceMessage(player.Continent, AvatarAction.ObjectHeld(player.GUID, player.LastDrawnSlot))
|
||||
|
||||
|
||||
// Ignore non-equipment holsters
|
||||
//todo: check current suit holster slots?
|
||||
if(held_holsters >= 0 && held_holsters < 5) {
|
||||
|
|
@ -2598,7 +2601,6 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
}
|
||||
case None => ;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Stop using proximity terminals if player unholsters a weapon (which should re-trigger the proximity effect and re-holster the weapon)
|
||||
|
|
@ -2688,7 +2690,9 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
log.warn(s"RequestDestroy: not allowed to delete object $thing")
|
||||
|
||||
case None =>
|
||||
log.warn(s"RequestDestroy: object $object_guid not found")
|
||||
if(ResolveProjectileEntry(object_guid.guid - Projectile.BaseUID, ProjectileResolution.MissedShot).isEmpty) {
|
||||
log.warn(s"RequestDestroy: object $object_guid not found")
|
||||
}
|
||||
}
|
||||
|
||||
case msg @ ObjectDeleteMessage(object_guid, unk1) =>
|
||||
|
|
@ -3137,8 +3141,8 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
|
||||
case msg @ WeaponFireMessage(seq_time, weapon_guid, projectile_guid, shot_origin, unk1, unk2, unk3, unk4, unk5, unk6, unk7) =>
|
||||
log.info("WeaponFire: " + msg)
|
||||
FindWeapon match {
|
||||
case Some(tool : Tool) =>
|
||||
FindContainedWeapon match {
|
||||
case (Some(obj), Some(tool : Tool)) =>
|
||||
if(tool.Magazine <= 0) { //safety: enforce ammunition depletion
|
||||
tool.Magazine = 0
|
||||
sendResponse(InventoryStateMessage(tool.AmmoSlot.Box.GUID, weapon_guid, 0))
|
||||
|
|
@ -3149,7 +3153,17 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
}
|
||||
else { //shooting
|
||||
tool.Discharge
|
||||
//TODO other stuff?
|
||||
val projectileIndex = projectile_guid.guid - Projectile.BaseUID
|
||||
val ang = obj match {
|
||||
case _ : Player =>
|
||||
obj.Orientation //TODO upper body facing
|
||||
case _ : Vehicle =>
|
||||
tool.Orientation //TODO this is too simplistic
|
||||
case _ =>
|
||||
Vector3.Zero
|
||||
}
|
||||
projectiles(projectileIndex) =
|
||||
Some(Projectile(tool.Projectile, tool.Definition, shot_origin, ang))
|
||||
}
|
||||
case _ => ;
|
||||
}
|
||||
|
|
@ -3158,10 +3172,16 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
log.info("Lazing position: " + pos2.toString)
|
||||
|
||||
case msg @ HitMessage(seq_time, projectile_guid, unk1, hit_info, unk2, unk3, unk4) =>
|
||||
log.info("Hit: " + msg)
|
||||
log.info(s"Hit: $msg")
|
||||
ResolveProjectileEntry(projectile_guid.guid - Projectile.BaseUID, ProjectileResolution.Target)
|
||||
|
||||
case msg @ SplashHitMessage(unk1, unk2, unk3, unk4, unk5, unk6, unk7, unk8) =>
|
||||
log.info("SplashHitMessage: " + msg)
|
||||
case msg @ SplashHitMessage(seq_time, projectile_guid, explosion_pos, direct_victim_uid, unk3, projectile_vel, unk4, targets) =>
|
||||
log.info(s"Splash: $msg")
|
||||
ResolveProjectileEntry(projectile_guid.guid - Projectile.BaseUID, ProjectileResolution.Target)
|
||||
|
||||
case msg @ LashMessage(seq_time, killer_guid, victim_guid, projectile_guid, pos, unk1) =>
|
||||
log.info(s"Lash: $msg")
|
||||
ResolveProjectileEntry(projectile_guid.guid - Projectile.BaseUID, ProjectileResolution.Target)
|
||||
|
||||
case msg @ AvatarFirstTimeEventMessage(avatar_guid, object_guid, unk1, event_name) =>
|
||||
log.info("AvatarFirstTimeEvent: " + msg)
|
||||
|
|
@ -5229,6 +5249,28 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
}
|
||||
}
|
||||
|
||||
def ResolveProjectileEntry(index : Int, resolution : ProjectileResolution.Value) : Option[Projectile] = {
|
||||
if(0 <= index && index < projectiles.length) {
|
||||
val entry = projectiles(index)
|
||||
entry match {
|
||||
case None =>
|
||||
log.warn(s"ResolveProjectile: expected projectile, but ${Projectile.BaseUID + index} not found")
|
||||
None
|
||||
case Some(projectile) =>
|
||||
projectile.resolution match {
|
||||
case ProjectileResolution.Unresolved => ;
|
||||
case _ =>
|
||||
log.warn(s"ResolveProjectileEntry: ${projectile.profile.ProjectileType} projectile found but reports to already be resolved")
|
||||
}
|
||||
projectiles(index) = Some(projectile.Resolve(resolution))
|
||||
projectiles(index)
|
||||
}
|
||||
}
|
||||
else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
def failWithError(error : String) = {
|
||||
log.error(error)
|
||||
sendResponse(ConnectionClose())
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue