diff --git a/src/main/scala/net/psforever/actors/session/csr/WeaponAndProjectileLogic.scala b/src/main/scala/net/psforever/actors/session/csr/WeaponAndProjectileLogic.scala index b8c0b6485..ea81f368c 100644 --- a/src/main/scala/net/psforever/actors/session/csr/WeaponAndProjectileLogic.scala +++ b/src/main/scala/net/psforever/actors/session/csr/WeaponAndProjectileLogic.scala @@ -127,14 +127,14 @@ class WeaponAndProjectileLogic(val ops: WeaponAndProjectileOperations, implicit val list = ops.composeDirectDamageInformation(pkt) if (!player.spectator) { list.foreach { - case (target, projectile, _, _) => - ops.resolveProjectileInteraction(target, projectile, DamageResolution.Hit, target.Position) + case (target, projectile, _, targetPos) => + ops.resolveProjectileInteractionAndProxy(target, projectile, DamageResolution.Hit, targetPos) } //... if (list.isEmpty) { ops.handleProxyDamage(pkt.projectile_guid, pkt.hit_info.map(_.hit_pos).getOrElse(Vector3.Zero)).foreach { - case (target, proxy, hitPos, _) => - ops.resolveProjectileInteraction(target, proxy, DamageResolution.Hit, hitPos) + case (target, proxy, _, targetPos) => + ops.resolveProjectileInteraction(target, proxy, DamageResolution.Hit, targetPos) } } } @@ -157,12 +157,12 @@ class WeaponAndProjectileLogic(val ops: WeaponAndProjectileOperations, implicit //... val (direct, others) = list.partition { case (_, _, hitPos, targetPos) => hitPos == targetPos } direct.foreach { - case (target, _, _, _) => - ops.resolveProjectileInteraction(target, projectile, resolution1, target.Position) + case (target, _, _, targetPos) => + ops.resolveProjectileInteractionAndProxy(target, projectile, resolution1, targetPos) } others.foreach { - case (target, _, _, _) => - ops.resolveProjectileInteraction(target, projectile, resolution2, target.Position) + case (target, _, _, targetPos) => + ops.resolveProjectileInteraction(target, projectile, resolution2, targetPos) } //... if ( @@ -183,11 +183,11 @@ class WeaponAndProjectileLogic(val ops: WeaponAndProjectileOperations, implicit if (profile.ExistsOnRemoteClients && projectile.HasGUID) { continent.Projectile ! ZoneProjectile.Remove(projectileGuid) } - } - //... - ops.handleProxyDamage(pkt.projectile_uid, pkt.projectile_pos).foreach { - case (target, proxy, hitPos, _) => - ops.resolveProjectileInteraction(target, proxy, DamageResolution.Splash, hitPos) + } else { + ops.handleProxyDamage(pkt.projectile_uid, pkt.projectile_pos).foreach { + case (target, proxy, _, targetPos) => + ops.resolveProjectileInteraction(target, proxy, DamageResolution.Splash, targetPos) + } } } } diff --git a/src/main/scala/net/psforever/actors/session/normal/WeaponAndProjectileLogic.scala b/src/main/scala/net/psforever/actors/session/normal/WeaponAndProjectileLogic.scala index 6ce96411b..8648046d8 100644 --- a/src/main/scala/net/psforever/actors/session/normal/WeaponAndProjectileLogic.scala +++ b/src/main/scala/net/psforever/actors/session/normal/WeaponAndProjectileLogic.scala @@ -144,9 +144,9 @@ class WeaponAndProjectileLogic(val ops: WeaponAndProjectileOperations, implicit val projectileGuid = pkt.projectile_guid val list = ops.composeDirectDamageInformation(pkt) .collect { - case (target, projectile, hitPos, _) => - ops.checkForHitPositionDiscrepancy(projectileGuid, hitPos, target) - ops.resolveProjectileInteraction(target, projectile, DamageResolution.Hit, hitPos) + case (target, projectile, hitPos, targetPos) => + ops.checkForHitPositionDiscrepancy(projectileGuid, hitPos, targetPos) + ops.resolveProjectileInteractionAndProxy(target, projectile, DamageResolution.Hit, hitPos) projectile } //... @@ -174,9 +174,9 @@ class WeaponAndProjectileLogic(val ops: WeaponAndProjectileOperations, implicit //... val (direct, others) = list.partition { case (_, _, hitPos, targetPos) => hitPos == targetPos } direct.foreach { - case (target, _, hitPos, _) => - ops.checkForHitPositionDiscrepancy(projectileGuid, hitPos, target) - ops.resolveProjectileInteraction(target, projectile, resolution1, hitPos) + case (target, _, hitPos, targetPos) => + ops.checkForHitPositionDiscrepancy(projectileGuid, hitPos, targetPos) + ops.resolveProjectileInteractionAndProxy(target, projectile, resolution1, hitPos) } others.foreach { case (target, _, hitPos, _) => @@ -202,19 +202,19 @@ class WeaponAndProjectileLogic(val ops: WeaponAndProjectileOperations, implicit //cleanup continent.Projectile ! ZoneProjectile.Remove(projectile.GUID) } - } - //... - ops.handleProxyDamage(pkt.projectile_uid, pkt.projectile_pos).foreach { - case (target, proxy, hitPos, _) => - ops.resolveProjectileInteraction(target, proxy, DamageResolution.Splash, hitPos) + } else { + ops.handleProxyDamage(pkt.projectile_uid, pkt.projectile_pos).foreach { + case (target, proxy, hitPos, _) => + ops.resolveProjectileInteraction(target, proxy, DamageResolution.Splash, hitPos) + } } } def handleLashHit(pkt: LashMessage): Unit = { val list = ops.composeLashDamageInformation(pkt) list.foreach { - case (target, projectile, hitPos, _) => - ops.checkForHitPositionDiscrepancy(projectile.GUID, hitPos, target) + case (target, projectile, hitPos, targetPos) => + ops.checkForHitPositionDiscrepancy(projectile.GUID, hitPos, targetPos) ops.resolveProjectileInteraction(target, projectile, DamageResolution.Lash, hitPos) } } @@ -223,8 +223,8 @@ class WeaponAndProjectileLogic(val ops: WeaponAndProjectileOperations, implicit val list = ops.composeAIDamageInformation(pkt) if (ops.confirmAIDamageTarget(pkt, list.map(_._1))) { list.foreach { - case (target, projectile, hitPos, _) => - ops.checkForHitPositionDiscrepancy(pkt.attacker_guid, hitPos, target) + case (target, projectile, hitPos, targetPos) => + ops.checkForHitPositionDiscrepancy(pkt.attacker_guid, hitPos, targetPos) ops.resolveProjectileInteraction(target, projectile, DamageResolution.Hit, hitPos) } } diff --git a/src/main/scala/net/psforever/actors/session/support/WeaponAndProjectileOperations.scala b/src/main/scala/net/psforever/actors/session/support/WeaponAndProjectileOperations.scala index f85576942..a6ab82fd4 100644 --- a/src/main/scala/net/psforever/actors/session/support/WeaponAndProjectileOperations.scala +++ b/src/main/scala/net/psforever/actors/session/support/WeaponAndProjectileOperations.scala @@ -513,6 +513,7 @@ class WeaponAndProjectileOperations( hit_info match { case Some(hitInfo) => val hitPos = hitInfo.hit_pos + projectile.Position = hitPos sessionLogic.validObject(hitInfo.hitobject_guid, decorator = "Hit/hitInfo") match { case _ if projectile.profile == GlobalDefinitions.flail_projectile => val radius = projectile.profile.DamageRadius * projectile.profile.DamageRadius @@ -522,7 +523,7 @@ class WeaponAndProjectileOperations( .map(target => (target, projectile, hitPos, target.Position)) case Some(target: PlanetSideGameObject with FactionAffinity with Vitality) => - List((target, projectile, hitInfo.shot_origin, hitPos)) + List((target, projectile, hitPos, target.Position)) case None => Nil @@ -585,7 +586,9 @@ class WeaponAndProjectileOperations( FindProjectileEntry(projectile_guid) .flatMap { projectile => - sessionLogic + //projectile may still be moving, and may lash other targets in the future when in a different position + projectile.Position = hit_pos + sessionLogic .validObject(victim_guid, decorator = "LashHit/victim_guid") .collect { case target: PlanetSideGameObject with FactionAffinity with Vitality => @@ -826,6 +829,26 @@ class WeaponAndProjectileOperations( context.system.scheduler.scheduleOnce(500.milliseconds) { explosionFunc() } } + /** + * Find a projectile with the given globally unique identifier and mark it as a resolved shot. + * A `Resolved` shot has either encountered an obstacle or is being cleaned up for not finding an obstacle. + * Check if we are required to deal with damage proxy management as well. + * @param projectile projectile + * @param resolution resolution status to promote the projectile + * @return package that contains information about the damage + */ + def resolveProjectileInteractionAndProxy( + target: PlanetSideGameObject with FactionAffinity with Vitality, + projectile: Projectile, + resolution: DamageResolution.Value, + hitPosition: Vector3 + ): Option[DamageInteraction] = { + if (projectile.profile.DamageProxyOnDirectHit.exists(_.test(target))) { + handleProxyDamage(projectile, hitPosition) + } + resolveProjectileInteraction(target, projectile, resolution, hitPosition) + } + /** * Find a projectile with the given globally unique identifier and mark it as a resolved shot. * A `Resolved` shot has either encountered an obstacle or is being cleaned up for not finding an obstacle. @@ -842,9 +865,6 @@ class WeaponAndProjectileOperations( if (projectile.isMiss) { None } else { - if (projectile.profile.DamageProxyOnDirectHit.exists(_.test(target))) { - handleProxyDamage(projectile, hitPosition) - } val outProjectile = ProjectileQuality.modifiers(projectile, resolution, target, hitPosition, Some(player)) if (projectile.tool_def.Size == EquipmentSize.Melee && outProjectile.quality == ProjectileQuality.Modified(25)) { avatarActor ! AvatarActor.ConsumeStamina(10) @@ -1462,15 +1482,23 @@ class WeaponAndProjectileOperations( } def checkForHitPositionDiscrepancy( - projectile_guid: PlanetSideGUID, - hitPos: Vector3, + projectileGuid: PlanetSideGUID, + hitPosition: Vector3, target: PlanetSideGameObject with Vitality ): Unit = { - val hitPositionDiscrepancy = Vector3.DistanceSquared(hitPos, target.Position) + checkForHitPositionDiscrepancy(projectileGuid, hitPosition, target.Position) + } + + def checkForHitPositionDiscrepancy( + projectileGuid: PlanetSideGUID, + hitPosition: Vector3, + targetPosition: Vector3 + ): Unit = { + val hitPositionDiscrepancy = Vector3.DistanceSquared(hitPosition, targetPosition) if (hitPositionDiscrepancy > Config.app.antiCheat.hitPositionDiscrepancyThreshold) { // If the target position on the server does not match the position where the projectile landed within reason there may be foul play log.warn( - s"${player.Name}'s shot #${projectile_guid.guid} has hit discrepancy with target. Target: ${target.Position}, Reported: $hitPos, Distance: $hitPositionDiscrepancy / ${math.sqrt(hitPositionDiscrepancy).toFloat}; suspect" + s"${player.Name}'s shot #${projectileGuid.guid} has hit discrepancy with target. Target: $targetPosition, Reported: $hitPosition, Distance: $hitPositionDiscrepancy / ${math.sqrt(hitPositionDiscrepancy).toFloat}; suspect" ) } }