mirror of
https://github.com/psforever/PSF-LoginServer.git
synced 2026-07-16 08:55:18 +00:00
redid DamageFeedbackMessage packet because I thought I could use it for something; didn't use it for anything; boomers are no longer responsive to explosive sympathy
This commit is contained in:
parent
82222d7c0b
commit
fa9ba7e7da
7 changed files with 216 additions and 261 deletions
|
|
@ -162,8 +162,7 @@ class GeneralLogic(val ops: GeneralOperations, implicit val context: ActorContex
|
||||||
case None => ()
|
case None => ()
|
||||||
}
|
}
|
||||||
val eagleEye: Boolean = ops.canSeeReallyFar
|
val eagleEye: Boolean = ops.canSeeReallyFar
|
||||||
val isNotVisible: Boolean = player.spectator ||
|
val isNotVisible: Boolean = sessionLogic.zoning.zoningStatus == Zoning.Status.Deconstructing ||
|
||||||
sessionLogic.zoning.zoningStatus == Zoning.Status.Deconstructing ||
|
|
||||||
(player.isAlive && sessionLogic.zoning.spawn.deadState == DeadState.RespawnTime)
|
(player.isAlive && sessionLogic.zoning.spawn.deadState == DeadState.RespawnTime)
|
||||||
continent.AvatarEvents ! AvatarServiceMessage(
|
continent.AvatarEvents ! AvatarServiceMessage(
|
||||||
continent.id,
|
continent.id,
|
||||||
|
|
@ -716,7 +715,7 @@ class GeneralLogic(val ops: GeneralOperations, implicit val context: ActorContex
|
||||||
val (target1, target2, bailProtectStatus, velocity) = (ctype, sessionLogic.validObject(p, decorator = "GenericCollision/Primary")) match {
|
val (target1, target2, bailProtectStatus, velocity) = (ctype, sessionLogic.validObject(p, decorator = "GenericCollision/Primary")) match {
|
||||||
case (CollisionIs.OfInfantry, out @ Some(user: Player))
|
case (CollisionIs.OfInfantry, out @ Some(user: Player))
|
||||||
if user == player =>
|
if user == player =>
|
||||||
val bailStatus = session.flying || player.spectator || session.speed > 1f || player.BailProtection
|
val bailStatus = session.flying || session.speed > 1f || player.BailProtection
|
||||||
player.BailProtection = false
|
player.BailProtection = false
|
||||||
val v = if (player.avatar.implants.exists {
|
val v = if (player.avatar.implants.exists {
|
||||||
case Some(implant) => implant.definition.implantType == ImplantType.Surge && implant.active
|
case Some(implant) => implant.definition.implantType == ImplantType.Surge && implant.active
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,11 @@ package net.psforever.objects
|
||||||
import akka.actor.{ActorContext, Props}
|
import akka.actor.{ActorContext, Props}
|
||||||
import net.psforever.objects.ce.{Deployable, DeployedItem}
|
import net.psforever.objects.ce.{Deployable, DeployedItem}
|
||||||
import net.psforever.objects.guid.{GUIDTask, TaskWorkflow}
|
import net.psforever.objects.guid.{GUIDTask, TaskWorkflow}
|
||||||
|
import net.psforever.objects.serverobject.affinity.FactionAffinity
|
||||||
|
import net.psforever.objects.serverobject.damage.Damageable
|
||||||
import net.psforever.objects.serverobject.{CommonMessages, PlanetSideServerObject}
|
import net.psforever.objects.serverobject.{CommonMessages, PlanetSideServerObject}
|
||||||
import net.psforever.objects.sourcing.{PlayerSource, SourceEntry}
|
import net.psforever.objects.sourcing.{PlayerSource, SourceEntry}
|
||||||
|
import net.psforever.objects.vital.Vitality
|
||||||
import net.psforever.objects.vital.etc.TriggerUsedReason
|
import net.psforever.objects.vital.etc.TriggerUsedReason
|
||||||
import net.psforever.objects.vital.interaction.DamageInteraction
|
import net.psforever.objects.vital.interaction.DamageInteraction
|
||||||
import net.psforever.objects.zones.Zone
|
import net.psforever.objects.zones.Zone
|
||||||
|
|
@ -58,8 +61,7 @@ class BoomerDeployableControl(mine: BoomerDeployable)
|
||||||
case CommonMessages.Use(player, Some(trigger: BoomerTrigger)) if mine.Trigger.contains(trigger) =>
|
case CommonMessages.Use(player, Some(trigger: BoomerTrigger)) if mine.Trigger.contains(trigger) =>
|
||||||
// the trigger damages the mine, which sets it off, which causes an explosion
|
// the trigger damages the mine, which sets it off, which causes an explosion
|
||||||
// think of this as an initiator to the proper explosion
|
// think of this as an initiator to the proper explosion
|
||||||
mine.Destroyed = true
|
HandleDamage(
|
||||||
ExplosiveDeployableControl.DamageResolution(
|
|
||||||
mine,
|
mine,
|
||||||
DamageInteraction(
|
DamageInteraction(
|
||||||
SourceEntry(mine),
|
SourceEntry(mine),
|
||||||
|
|
@ -68,8 +70,7 @@ class BoomerDeployableControl(mine: BoomerDeployable)
|
||||||
).calculate()(mine),
|
).calculate()(mine),
|
||||||
damage = 0
|
damage = 0
|
||||||
)
|
)
|
||||||
|
case _ => ()
|
||||||
case _ => ;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def loseOwnership(@unused faction: PlanetSideEmpire.Value): Unit = {
|
def loseOwnership(@unused faction: PlanetSideEmpire.Value): Unit = {
|
||||||
|
|
@ -97,14 +98,27 @@ class BoomerDeployableControl(mine: BoomerDeployable)
|
||||||
container.Slot(index).Equipment = None
|
container.Slot(index).Equipment = None
|
||||||
case Some(Zone.EquipmentIs.OnGround()) =>
|
case Some(Zone.EquipmentIs.OnGround()) =>
|
||||||
zone.Ground ! Zone.Ground.RemoveItem(guid)
|
zone.Ground ! Zone.Ground.RemoveItem(guid)
|
||||||
case _ => ;
|
case _ => ()
|
||||||
}
|
}
|
||||||
zone.AvatarEvents! AvatarServiceMessage(
|
zone.AvatarEvents! AvatarServiceMessage(
|
||||||
zone.id,
|
zone.id,
|
||||||
AvatarAction.ObjectDelete(Service.defaultPlayerGUID, guid)
|
AvatarAction.ObjectDelete(Service.defaultPlayerGUID, guid)
|
||||||
)
|
)
|
||||||
TaskWorkflow.execute(GUIDTask.unregisterObject(zone.GUID, trigger))
|
TaskWorkflow.execute(GUIDTask.unregisterObject(zone.GUID, trigger))
|
||||||
case None => ;
|
case None => ()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Boomers are not bothered by explosive sympathy
|
||||||
|
* but can still be affected by sources of jammering.
|
||||||
|
* @param obj the entity being damaged
|
||||||
|
* @param damage the amount of damage
|
||||||
|
* @param data historical information about the damage
|
||||||
|
* @return `true`, if the target can be affected;
|
||||||
|
* `false`, otherwise
|
||||||
|
*/
|
||||||
|
override def CanDetonate(obj: Vitality with FactionAffinity, damage: Int, data: DamageInteraction): Boolean = {
|
||||||
|
!mine.Destroyed && (data.cause.isInstanceOf[TriggerUsedReason] || Damageable.CanJammer(obj, data))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -90,14 +90,34 @@ abstract class ExplosiveDeployableControl(mine: ExplosiveDeployable)
|
||||||
val originalHealth = mine.Health
|
val originalHealth = mine.Health
|
||||||
val cause = applyDamageTo(mine)
|
val cause = applyDamageTo(mine)
|
||||||
val damage = originalHealth - mine.Health
|
val damage = originalHealth - mine.Health
|
||||||
if (CanDetonate(mine, damage, cause.interaction)) {
|
if (Interaction(mine, damage, cause.interaction)) {
|
||||||
ExplosiveDeployableControl.DamageResolution(mine, cause, damage)
|
HandleDamage(mine, cause, damage)
|
||||||
} else {
|
} else {
|
||||||
mine.Health = originalHealth
|
mine.Health = originalHealth
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def Interaction(obj: Vitality with FactionAffinity, damage: Int, data: DamageInteraction): Boolean = {
|
||||||
|
!mine.Destroyed && (if (damage == 0 && data.cause.source.SympatheticExplosion) {
|
||||||
|
Damageable.CanDamageOrJammer(obj, damage = 1, data)
|
||||||
|
} else {
|
||||||
|
Damageable.CanDamageOrJammer(obj, damage, data)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
final def HandleDamage(target: ExplosiveDeployable, cause: DamageResult, damage: Int): Unit = {
|
||||||
|
target.LogActivity(cause)
|
||||||
|
if (CanDetonate(target, damage, cause.interaction)) {
|
||||||
|
ExplosiveDeployableControl.explodes(target, cause)
|
||||||
|
ExplosiveDeployableControl.DestructionAwareness(target, cause)
|
||||||
|
} else if (target.Health == 0) {
|
||||||
|
ExplosiveDeployableControl.DestructionAwareness(target, cause)
|
||||||
|
} else {
|
||||||
|
ExplosiveDeployableControl.DamageAwareness(target, cause, damage)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A supplement for checking target susceptibility
|
* A supplement for checking target susceptibility
|
||||||
* to account for sympathetic explosives even if there is no damage.
|
* to account for sympathetic explosives even if there is no damage.
|
||||||
|
|
@ -117,6 +137,11 @@ abstract class ExplosiveDeployableControl(mine: ExplosiveDeployable)
|
||||||
Damageable.CanDamageOrJammer(mine, damage, data)
|
Damageable.CanDamageOrJammer(mine, damage, data)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def explode(target: ExplosiveDeployable, cause: DamageResult): Unit = {
|
||||||
|
ExplosiveDeployableControl.explodes(target, cause)
|
||||||
|
ExplosiveDeployableControl.DestructionAwareness(target, cause)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
object ExplosiveDeployableControl {
|
object ExplosiveDeployableControl {
|
||||||
|
|
@ -126,14 +151,8 @@ object ExplosiveDeployableControl {
|
||||||
* @param cause na
|
* @param cause na
|
||||||
* @param damage na
|
* @param damage na
|
||||||
*/
|
*/
|
||||||
def DamageResolution(target: ExplosiveDeployable, cause: DamageResult, damage: Int): Unit = {
|
def DamageAwareness(target: ExplosiveDeployable, cause: DamageResult, damage: Int): Unit = {
|
||||||
target.LogActivity(cause)
|
if (!target.Jammed && Damageable.CanJammer(target, cause.interaction)) {
|
||||||
if (cause.interaction.cause.source.SympatheticExplosion) {
|
|
||||||
explodes(target, cause)
|
|
||||||
DestructionAwareness(target, cause)
|
|
||||||
} else if (target.Health == 0) {
|
|
||||||
DestructionAwareness(target, cause)
|
|
||||||
} else if (!target.Jammed && Damageable.CanJammer(target, cause.interaction)) {
|
|
||||||
if ( {
|
if ( {
|
||||||
target.Jammed = cause.interaction.cause match {
|
target.Jammed = cause.interaction.cause match {
|
||||||
case o: ProjectileReason =>
|
case o: ProjectileReason =>
|
||||||
|
|
@ -158,6 +177,7 @@ object ExplosiveDeployableControl {
|
||||||
* @param cause na
|
* @param cause na
|
||||||
*/
|
*/
|
||||||
def explodes(target: Damageable.Target, cause: DamageResult): Unit = {
|
def explodes(target: Damageable.Target, cause: DamageResult): Unit = {
|
||||||
|
target.Destroyed = true
|
||||||
target.Health = 1 // short-circuit logic in DestructionAwareness
|
target.Health = 1 // short-circuit logic in DestructionAwareness
|
||||||
val zone = target.Zone
|
val zone = target.Zone
|
||||||
zone.Activity ! Zone.HotSpot.Activity(cause)
|
zone.Activity ! Zone.HotSpot.Activity(cause)
|
||||||
|
|
@ -268,7 +288,7 @@ class MineDeployableControl(mine: ExplosiveDeployable)
|
||||||
mine.Definition.innateDamage.map { _.DamageRadius }.getOrElse(mine.Definition.triggerRadius)
|
mine.Definition.innateDamage.map { _.DamageRadius }.getOrElse(mine.Definition.triggerRadius)
|
||||||
))
|
))
|
||||||
|
|
||||||
case _ => ;
|
case _ => ()
|
||||||
}
|
}
|
||||||
|
|
||||||
override def finalizeDeployable(callback: ActorRef): Unit = {
|
override def finalizeDeployable(callback: ActorRef): Unit = {
|
||||||
|
|
@ -287,33 +307,36 @@ class MineDeployableControl(mine: ExplosiveDeployable)
|
||||||
}
|
}
|
||||||
|
|
||||||
def setTriggered(instigator: Option[PlanetSideServerObject], delay: Long): Unit = {
|
def setTriggered(instigator: Option[PlanetSideServerObject], delay: Long): Unit = {
|
||||||
instigator match {
|
instigator
|
||||||
case Some(_) if isConstructed.contains(true) && setup.isCancelled =>
|
.collect {
|
||||||
//re-use the setup timer here
|
case _ if isConstructed.contains(true) && setup.isCancelled =>
|
||||||
import scala.concurrent.ExecutionContext.Implicits.global
|
//re-use the setup timer here
|
||||||
setup = context.system.scheduler.scheduleOnce(delay milliseconds, self, MineDeployableControl.Triggered())
|
import scala.concurrent.ExecutionContext.Implicits.global
|
||||||
case _ => ;
|
setup = context.system.scheduler.scheduleOnce(delay milliseconds, self, MineDeployableControl.Triggered())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def explodes(instigator: Option[PlanetSideServerObject]): Unit = {
|
def explodes(instigator: Option[PlanetSideServerObject]): Unit = {
|
||||||
instigator match {
|
instigator
|
||||||
case Some(_) =>
|
.collect {
|
||||||
//explosion
|
case _ =>
|
||||||
mine.Destroyed = true
|
//explosion
|
||||||
ExplosiveDeployableControl.DamageResolution(
|
mine.Destroyed = true
|
||||||
mine,
|
ExplosiveDeployableControl.DamageAwareness(
|
||||||
DamageInteraction(
|
mine,
|
||||||
SourceEntry(mine),
|
DamageInteraction(
|
||||||
MineDeployableControl.trippedMineReason(mine),
|
SourceEntry(mine),
|
||||||
mine.Position
|
MineDeployableControl.trippedMineReason(mine),
|
||||||
).calculate()(mine),
|
mine.Position
|
||||||
damage = 0
|
).calculate()(mine),
|
||||||
)
|
damage = 0
|
||||||
case None =>
|
)
|
||||||
|
}
|
||||||
|
.orElse {
|
||||||
//reset
|
//reset
|
||||||
setup = Default.Cancellable
|
setup = Default.Cancellable
|
||||||
}
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@ object GlobalDefinitionsDeployable {
|
||||||
|
|
||||||
boomer.Name = "boomer"
|
boomer.Name = "boomer"
|
||||||
boomer.Descriptor = "Boomers"
|
boomer.Descriptor = "Boomers"
|
||||||
boomer.MaxHealth = 100
|
boomer.MaxHealth = 50
|
||||||
boomer.Damageable = true
|
boomer.Damageable = true
|
||||||
boomer.DamageableByFriendlyFire = false
|
boomer.DamageableByFriendlyFire = false
|
||||||
boomer.Repairable = false
|
boomer.Repairable = false
|
||||||
|
|
@ -58,7 +58,7 @@ object GlobalDefinitionsDeployable {
|
||||||
|
|
||||||
he_mine.Name = "he_mine"
|
he_mine.Name = "he_mine"
|
||||||
he_mine.Descriptor = "Mines"
|
he_mine.Descriptor = "Mines"
|
||||||
he_mine.MaxHealth = 100
|
he_mine.MaxHealth = 50
|
||||||
he_mine.Damageable = true
|
he_mine.Damageable = true
|
||||||
he_mine.DamageableByFriendlyFire = false
|
he_mine.DamageableByFriendlyFire = false
|
||||||
he_mine.Repairable = false
|
he_mine.Repairable = false
|
||||||
|
|
@ -82,7 +82,7 @@ object GlobalDefinitionsDeployable {
|
||||||
|
|
||||||
jammer_mine.Name = "jammer_mine"
|
jammer_mine.Name = "jammer_mine"
|
||||||
jammer_mine.Descriptor = "JammerMines"
|
jammer_mine.Descriptor = "JammerMines"
|
||||||
jammer_mine.MaxHealth = 100
|
jammer_mine.MaxHealth = 50
|
||||||
jammer_mine.Damageable = true
|
jammer_mine.Damageable = true
|
||||||
jammer_mine.DamageableByFriendlyFire = false
|
jammer_mine.DamageableByFriendlyFire = false
|
||||||
jammer_mine.Repairable = false
|
jammer_mine.Repairable = false
|
||||||
|
|
|
||||||
|
|
@ -50,7 +50,6 @@ final case class TriggerUsedReason(user: PlayerSource, item_guid: PlanetSideGUID
|
||||||
object TriggerUsedReason {
|
object TriggerUsedReason {
|
||||||
private val triggered = new DamageProperties {
|
private val triggered = new DamageProperties {
|
||||||
Damage0 = 1 //token damage
|
Damage0 = 1 //token damage
|
||||||
SympatheticExplosion = true //sets off a boomer
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** basic damage, no resisting, quick and simple */
|
/** basic damage, no resisting, quick and simple */
|
||||||
|
|
|
||||||
|
|
@ -1,51 +1,55 @@
|
||||||
// Copyright (c) 2019 PSForever
|
// Copyright (c) 2019 PSForever
|
||||||
package net.psforever.packet.game
|
package net.psforever.packet.game
|
||||||
|
|
||||||
|
import net.psforever.packet.GamePacketOpcode.Type
|
||||||
import net.psforever.packet.{GamePacketOpcode, Marshallable, PacketHelpers, PlanetSideGamePacket}
|
import net.psforever.packet.{GamePacketOpcode, Marshallable, PacketHelpers, PlanetSideGamePacket}
|
||||||
import net.psforever.types.PlanetSideGUID
|
import net.psforever.types.PlanetSideGUID
|
||||||
import scodec.Codec
|
import scodec.bits.BitVector
|
||||||
|
import scodec.{Attempt, Codec}
|
||||||
import scodec.codecs._
|
import scodec.codecs._
|
||||||
import shapeless.{::, HNil}
|
import shapeless.{::, HNil}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* na
|
* na
|
||||||
* @param unk1 na
|
* @param unk1 na
|
||||||
* @param unk2 if no global unique identifier (below), the alternate identification for the entity
|
* @param unk2 a modifier that customizes one of the values for the `unk2...` determination values;
|
||||||
* @param unk2a the global unique identifier of the entity inflicting the damage
|
* when not using the GUID field, `true` when using the string field
|
||||||
* @param unk2b if no global unique identifier (above), the name of the entity inflicting the damage
|
* @param unk2a the global unique identifier of the entity inflicting the damage
|
||||||
* @param unk2c if no global unique identifier (above), the object type of the entity inflicting the damage
|
* @param unk2b if no global unique identifier (above), the name of the entity inflicting the damage
|
||||||
* @param unk3 if no global unique identifier (below), the alternate identification for the entity
|
* @param unk2c if no global unique identifier (above), the object type of the entity inflicting the damage
|
||||||
* @param unk3a the global unique identifier of the entity absorbing the damage
|
* @param unk3 a modifier that customizes one of the values for the `unk3...` determination values;
|
||||||
* @param unk3b if no global unique identifier (above), the name of the entity absorbing the damage
|
* when not using the GUID field, `true` when using the string field
|
||||||
* @param unk3c if no global unique identifier (above), the object type of the entity absorbing the damage
|
* @param unk3a the global unique identifier of the entity absorbing the damage
|
||||||
* @param unk3d na
|
* @param unk3b if no global unique identifier (above), the name of the entity absorbing the damage
|
||||||
* @param unk4 an indicator for the target-specific vital statistic being affected
|
* @param unk3c if no global unique identifier (above), the object type of the entity absorbing the damage
|
||||||
* @param unk5 the amount of damage
|
* @param unk3d na
|
||||||
* @param unk6 na
|
* @param unk4 an indicator for the target-specific vital statistic being affected
|
||||||
*/
|
* @param unk5 the amount of damage
|
||||||
|
* @param unk6 na
|
||||||
|
*/
|
||||||
final case class DamageFeedbackMessage(
|
final case class DamageFeedbackMessage(
|
||||||
unk1: Int,
|
unk1: Int,
|
||||||
unk2: Boolean,
|
unk2: Option[Boolean],
|
||||||
unk2a: Option[PlanetSideGUID],
|
unk2a: Option[PlanetSideGUID],
|
||||||
unk2b: Option[String],
|
unk2b: Option[String],
|
||||||
unk2c: Option[Int],
|
unk2c: Option[Int],
|
||||||
unk3: Boolean,
|
unk3: Option[Boolean],
|
||||||
unk3a: Option[PlanetSideGUID],
|
unk3a: Option[PlanetSideGUID],
|
||||||
unk3b: Option[String],
|
unk3b: Option[String],
|
||||||
unk3c: Option[Int],
|
unk3c: Option[Int],
|
||||||
unk3d: Option[Int],
|
unk3d: Option[Int],
|
||||||
unk4: Int,
|
unk4: Int,
|
||||||
unk5: Long,
|
unk5: Long,
|
||||||
unk6: Int
|
unk6: Int
|
||||||
) extends PlanetSideGamePacket {
|
) extends PlanetSideGamePacket {
|
||||||
assert(
|
assert(
|
||||||
{
|
{
|
||||||
val unk2aEmpty = unk2a.isEmpty
|
val unk2aEmpty = unk2a.isEmpty
|
||||||
val unk2bEmpty = unk2b.isEmpty
|
val unk2bEmpty = unk2b.isEmpty
|
||||||
val unk2cEmpty = unk2c.isEmpty
|
val unk2cEmpty = unk2c.isEmpty
|
||||||
if (unk2a.nonEmpty) unk2bEmpty && unk2cEmpty
|
if (!unk2aEmpty) unk2bEmpty && unk2cEmpty
|
||||||
else if (unk2b.nonEmpty) unk2 && unk2aEmpty && unk2cEmpty
|
else if (!unk2bEmpty) unk2aEmpty && unk2cEmpty
|
||||||
else unk2aEmpty && !unk2 && unk2bEmpty && unk2c.nonEmpty
|
else unk2aEmpty && unk2bEmpty && !unk2cEmpty
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
assert(
|
assert(
|
||||||
|
|
@ -53,58 +57,104 @@ final case class DamageFeedbackMessage(
|
||||||
val unk3aEmpty = unk3a.isEmpty
|
val unk3aEmpty = unk3a.isEmpty
|
||||||
val unk3bEmpty = unk3b.isEmpty
|
val unk3bEmpty = unk3b.isEmpty
|
||||||
val unk3cEmpty = unk3c.isEmpty
|
val unk3cEmpty = unk3c.isEmpty
|
||||||
if (unk3a.nonEmpty) unk3bEmpty && unk3cEmpty
|
if (!unk3aEmpty) unk3bEmpty && unk3cEmpty
|
||||||
else if (unk3b.nonEmpty) unk3 && unk3aEmpty && unk3cEmpty
|
else if (!unk3bEmpty) unk3aEmpty && unk3cEmpty
|
||||||
else unk3aEmpty && !unk3 && unk3bEmpty && unk3c.nonEmpty
|
else unk3aEmpty && unk3bEmpty && !unk3cEmpty
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
assert(unk3a.isEmpty == unk3d.nonEmpty)
|
assert(unk3a.isEmpty == unk3d.nonEmpty)
|
||||||
|
|
||||||
type Packet = DamageFeedbackMessage
|
type Packet = DamageFeedbackMessage
|
||||||
def opcode = GamePacketOpcode.DamageFeedbackMessage
|
def opcode: Type = GamePacketOpcode.DamageFeedbackMessage
|
||||||
def encode = DamageFeedbackMessage.encode(this)
|
def encode: Attempt[BitVector] = DamageFeedbackMessage.encode(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
object DamageFeedbackMessage extends Marshallable[DamageFeedbackMessage] {
|
object DamageFeedbackMessage extends Marshallable[DamageFeedbackMessage] {
|
||||||
def apply(unk1: Int,
|
def apply(
|
||||||
unk2: PlanetSideGUID,
|
unk1: Int,
|
||||||
unk3: PlanetSideGUID,
|
unk2a: Option[PlanetSideGUID],
|
||||||
unk4: Int,
|
unk2b: Option[String],
|
||||||
unk5: Long): DamageFeedbackMessage =
|
unk2c: Option[Int],
|
||||||
DamageFeedbackMessage(unk1, true, Some(unk2), None, None, true, Some(unk3), None, None, None, unk4, unk5, 0)
|
unk3a: Option[PlanetSideGUID],
|
||||||
|
unk3b: Option[String],
|
||||||
|
unk3c: Option[Int],
|
||||||
|
unk3d: Option[Int],
|
||||||
|
unk4: Int,
|
||||||
|
unk5: Long
|
||||||
|
): DamageFeedbackMessage = {
|
||||||
|
DamageFeedbackMessage(unk1, None, unk2a, unk2b, unk2c, None, unk3a, unk3b, unk3c, unk3d, unk4, unk5, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
def apply(
|
||||||
|
unk1: Int,
|
||||||
|
unk2: PlanetSideGUID,
|
||||||
|
unk3: PlanetSideGUID,
|
||||||
|
unk4: Int,
|
||||||
|
unk5: Long
|
||||||
|
): DamageFeedbackMessage = {
|
||||||
|
DamageFeedbackMessage(unk1, None, Some(unk2), None, None, None, Some(unk3), None, None, None, unk4, unk5, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
private case class EntryFields(
|
||||||
|
usesGuid: Boolean,
|
||||||
|
usesStr: Boolean,
|
||||||
|
guidOpt: Option[PlanetSideGUID],
|
||||||
|
strOpt: Option[String],
|
||||||
|
intOpt: Option[Int]
|
||||||
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* na
|
||||||
|
* @param adjustment na;
|
||||||
|
* can not be a negative number
|
||||||
|
* @return na
|
||||||
|
*/
|
||||||
|
private def entityFieldFormatCodec(adjustment: Int): Codec[EntryFields] = {
|
||||||
|
((bool :: bool) >>:~ { case usesGuid :: usesString :: HNil =>
|
||||||
|
conditional(usesGuid, PlanetSideGUID.codec) ::
|
||||||
|
conditional(!usesGuid && usesString, PacketHelpers.encodedWideStringAligned(adjustment)) ::
|
||||||
|
conditional(!usesGuid && !usesString, uintL(bits = 11))
|
||||||
|
}).xmap[EntryFields](
|
||||||
|
{
|
||||||
|
case (a :: b :: HNil) :: c :: d :: e :: HNil => EntryFields(a, b, c, d, e)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
case EntryFields(a, b, c, d, e) => (a :: b :: HNil) :: c :: d :: e :: HNil
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
implicit val codec: Codec[DamageFeedbackMessage] = (
|
implicit val codec: Codec[DamageFeedbackMessage] = (
|
||||||
("unk1" | uint4) ::
|
("unk1" | uint4) :: {
|
||||||
(bool >>:~ { u2 =>
|
entityFieldFormatCodec(adjustment = 4) >>:~ { fieldsA =>
|
||||||
bool >>:~ { u3 =>
|
val offset = if (fieldsA.usesGuid) { 0 } else if (fieldsA.usesStr) { 6 } else { 5 }
|
||||||
("unk2a" | conditional(u2, PlanetSideGUID.codec)) ::
|
entityFieldFormatCodec(offset) >>:~ { fieldsB =>
|
||||||
(("unk2b" | conditional(!u2 && u3, PacketHelpers.encodedWideStringAligned(6))) >>:~ { u2b =>
|
("unk3d" | conditional(!fieldsB.usesGuid, uint2)) ::
|
||||||
("unk2c" | conditional(!u2 && !u3, uintL(11))) ::
|
("unk4" | uint(bits = 3)) ::
|
||||||
(bool >>:~ { u5 =>
|
("unk5" | uint32L) ::
|
||||||
bool >>:~ { u6 =>
|
("unk6" | uint2)
|
||||||
("unk3a" | conditional(u5, PlanetSideGUID.codec)) ::
|
}
|
||||||
("unk3b" | conditional(
|
|
||||||
!u5 && u6,
|
|
||||||
PacketHelpers.encodedWideStringAligned(if (u2b.nonEmpty) 3 else 1)
|
|
||||||
)) ::
|
|
||||||
("unk3c" | conditional(!u5 && !u6, uintL(11))) ::
|
|
||||||
("unk3d" | conditional(!u5, uint2)) ::
|
|
||||||
("unk4" | uint(3)) ::
|
|
||||||
("unk5" | uint32L) ::
|
|
||||||
("unk6" | uint2)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
})
|
}).xmap[DamageFeedbackMessage](
|
||||||
).xmap[DamageFeedbackMessage](
|
|
||||||
{
|
{
|
||||||
case u1 :: _ :: u2 :: u2a :: u2b :: u2c :: _ :: u3 :: u3a :: u3b :: u3c :: u3d :: u4 :: u5 :: u6 :: HNil =>
|
case u1 :: EntryFields(_, u2, u2a, u2b, u2c) :: EntryFields(_, u3, u3a, u3b, u3c) :: u3d :: u4 :: u5 :: u6 :: HNil =>
|
||||||
DamageFeedbackMessage(u1, u2, u2a, u2b, u2c, u3, u3a, u3b, u3c, u3d, u4, u5, u6)
|
val u2False = if (u2a.nonEmpty && !u2) { Some(false) } else { None }
|
||||||
|
val u3False = if (u3a.nonEmpty && !u3) { Some(false) } else { None }
|
||||||
|
DamageFeedbackMessage(u1, u2False, u2a, u2b, u2c, u3False, u3a, u3b, u3c, u3d, u4, u5, u6)
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
case DamageFeedbackMessage(u1, u2, u2a, u2b, u2c, u3, u3a, u3b, u3c, u3d, u4, u5, u6) =>
|
case DamageFeedbackMessage(u1, u2, u2a, u2b, u2c, u3, u3a, u3b, u3c, u3d, u4, u5, u6) =>
|
||||||
u1 :: u2a.nonEmpty :: u2 :: u2a :: u2b :: u2c :: u3a.nonEmpty :: u3 :: u3a :: u3b :: u3c :: u3d :: u4 :: u5 :: u6 :: HNil
|
val(u2Boola, u2Boolb) = if (u2a.nonEmpty) {
|
||||||
|
(true, u2.getOrElse(true))
|
||||||
|
} else {
|
||||||
|
(false, u2b.nonEmpty)
|
||||||
|
}
|
||||||
|
val(u3Boola, u3Boolb) = if (u3a.nonEmpty) {
|
||||||
|
(true, u3.getOrElse(true))
|
||||||
|
} else {
|
||||||
|
(false, u3b.nonEmpty)
|
||||||
|
}
|
||||||
|
u1 :: EntryFields(u2Boola, u2Boolb, u2a, u2b, u2c) :: EntryFields(u3Boola, u3Boolb, u3a, u3b, u3c) :: u3d :: u4 :: u5 :: u6 :: HNil
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,13 +13,11 @@ class DamageFeedbackMessageTest extends Specification {
|
||||||
|
|
||||||
"decode (string 1)" in {
|
"decode (string 1)" in {
|
||||||
PacketCoding.decodePacket(string).require match {
|
PacketCoding.decodePacket(string).require match {
|
||||||
case DamageFeedbackMessage(unk1, unk2, unk2a, unk2b, unk2c, unk3, unk3a, unk3b, unk3c, unk3d, unk4, unk5, unk6) =>
|
case DamageFeedbackMessage(unk1, _, unk2a, unk2b, unk2c, _, unk3a, unk3b, unk3c, unk3d, unk4, unk5, unk6) =>
|
||||||
unk1 mustEqual 3
|
unk1 mustEqual 3
|
||||||
unk2 mustEqual true
|
|
||||||
unk2a.contains(PlanetSideGUID(2913)) mustEqual true
|
unk2a.contains(PlanetSideGUID(2913)) mustEqual true
|
||||||
unk2b.isEmpty mustEqual true
|
unk2b.isEmpty mustEqual true
|
||||||
unk2c.isEmpty mustEqual true
|
unk2c.isEmpty mustEqual true
|
||||||
unk3 mustEqual true
|
|
||||||
unk3a.contains(PlanetSideGUID(2913)) mustEqual true
|
unk3a.contains(PlanetSideGUID(2913)) mustEqual true
|
||||||
unk3b.isEmpty mustEqual true
|
unk3b.isEmpty mustEqual true
|
||||||
unk3c.isEmpty mustEqual true
|
unk3c.isEmpty mustEqual true
|
||||||
|
|
@ -34,13 +32,11 @@ class DamageFeedbackMessageTest extends Specification {
|
||||||
|
|
||||||
"decode (string 2)" in {
|
"decode (string 2)" in {
|
||||||
PacketCoding.decodePacket(string_2).require match {
|
PacketCoding.decodePacket(string_2).require match {
|
||||||
case DamageFeedbackMessage(unk1, unk2, unk2a, unk2b, unk2c, unk3, unk3a, unk3b, unk3c, unk3d, unk4, unk5, unk6) =>
|
case DamageFeedbackMessage(unk1, _, unk2a, unk2b, unk2c, _, unk3a, unk3b, unk3c, unk3d, unk4, unk5, unk6) =>
|
||||||
unk1 mustEqual 5
|
unk1 mustEqual 5
|
||||||
unk2 mustEqual true
|
|
||||||
unk2a.contains(PlanetSideGUID(2454)) mustEqual true
|
unk2a.contains(PlanetSideGUID(2454)) mustEqual true
|
||||||
unk2b.isEmpty mustEqual true
|
unk2b.isEmpty mustEqual true
|
||||||
unk2c.isEmpty mustEqual true
|
unk2c.isEmpty mustEqual true
|
||||||
unk3 mustEqual false
|
|
||||||
unk3a.contains(PlanetSideGUID(216)) mustEqual true
|
unk3a.contains(PlanetSideGUID(216)) mustEqual true
|
||||||
unk3b.isEmpty mustEqual true
|
unk3b.isEmpty mustEqual true
|
||||||
unk3c.isEmpty mustEqual true
|
unk3c.isEmpty mustEqual true
|
||||||
|
|
@ -56,18 +52,15 @@ class DamageFeedbackMessageTest extends Specification {
|
||||||
"encode (string 1)" in {
|
"encode (string 1)" in {
|
||||||
val msg = DamageFeedbackMessage(
|
val msg = DamageFeedbackMessage(
|
||||||
3,
|
3,
|
||||||
true,
|
|
||||||
Some(PlanetSideGUID(2913)),
|
Some(PlanetSideGUID(2913)),
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
true,
|
|
||||||
Some(PlanetSideGUID(2913)),
|
Some(PlanetSideGUID(2913)),
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
1,
|
1,
|
||||||
2,
|
2
|
||||||
0
|
|
||||||
)
|
)
|
||||||
val pkt = PacketCoding.encodePacket(msg).require.toByteVector
|
val pkt = PacketCoding.encodePacket(msg).require.toByteVector
|
||||||
|
|
||||||
|
|
@ -77,11 +70,11 @@ class DamageFeedbackMessageTest extends Specification {
|
||||||
"encode (string 2)" in {
|
"encode (string 2)" in {
|
||||||
val msg = DamageFeedbackMessage(
|
val msg = DamageFeedbackMessage(
|
||||||
5,
|
5,
|
||||||
true,
|
None,
|
||||||
Some(PlanetSideGUID(2454)),
|
Some(PlanetSideGUID(2454)),
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
false,
|
Some(false),
|
||||||
Some(PlanetSideGUID(216)),
|
Some(PlanetSideGUID(216)),
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
|
|
@ -99,252 +92,129 @@ class DamageFeedbackMessageTest extends Specification {
|
||||||
//unk2: no parameters
|
//unk2: no parameters
|
||||||
DamageFeedbackMessage(
|
DamageFeedbackMessage(
|
||||||
3,
|
3,
|
||||||
true,
|
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
true,
|
|
||||||
Some(PlanetSideGUID(2913)),
|
Some(PlanetSideGUID(2913)),
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
1,
|
1,
|
||||||
2,
|
2
|
||||||
0
|
|
||||||
) must throwA[AssertionError]
|
) must throwA[AssertionError]
|
||||||
//unk2: two exclusive parameters
|
//unk2: two exclusive parameters
|
||||||
DamageFeedbackMessage(
|
DamageFeedbackMessage(
|
||||||
3,
|
3,
|
||||||
true,
|
|
||||||
Some(PlanetSideGUID(2913)),
|
Some(PlanetSideGUID(2913)),
|
||||||
Some("error"),
|
Some("error"),
|
||||||
None,
|
None,
|
||||||
true,
|
|
||||||
Some(PlanetSideGUID(2913)),
|
Some(PlanetSideGUID(2913)),
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
1,
|
1,
|
||||||
2,
|
2
|
||||||
0
|
|
||||||
) must throwA[AssertionError]
|
) must throwA[AssertionError]
|
||||||
DamageFeedbackMessage(
|
DamageFeedbackMessage(
|
||||||
3,
|
3,
|
||||||
true,
|
|
||||||
Some(PlanetSideGUID(2913)),
|
Some(PlanetSideGUID(2913)),
|
||||||
None,
|
None,
|
||||||
Some(5),
|
Some(5),
|
||||||
true,
|
|
||||||
Some(PlanetSideGUID(2913)),
|
Some(PlanetSideGUID(2913)),
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
1,
|
1,
|
||||||
2,
|
2
|
||||||
0
|
|
||||||
) must throwA[AssertionError]
|
) must throwA[AssertionError]
|
||||||
DamageFeedbackMessage(
|
DamageFeedbackMessage(
|
||||||
3,
|
3,
|
||||||
true,
|
|
||||||
None,
|
None,
|
||||||
Some("error"),
|
Some("error"),
|
||||||
Some(5),
|
Some(5),
|
||||||
true,
|
|
||||||
Some(PlanetSideGUID(2913)),
|
Some(PlanetSideGUID(2913)),
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
1,
|
1,
|
||||||
2,
|
2
|
||||||
0
|
|
||||||
) must throwA[AssertionError]
|
) must throwA[AssertionError]
|
||||||
//unk2: all parameters
|
//unk2: all parameters
|
||||||
DamageFeedbackMessage(
|
DamageFeedbackMessage(
|
||||||
3,
|
3,
|
||||||
true,
|
|
||||||
Some(PlanetSideGUID(2913)),
|
Some(PlanetSideGUID(2913)),
|
||||||
Some("error"),
|
Some("error"),
|
||||||
Some(5),
|
Some(5),
|
||||||
true,
|
|
||||||
Some(PlanetSideGUID(2913)),
|
Some(PlanetSideGUID(2913)),
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
1,
|
1,
|
||||||
2,
|
2
|
||||||
0
|
|
||||||
) must throwA[AssertionError]
|
|
||||||
//unk2: mismatched flag for strings
|
|
||||||
DamageFeedbackMessage(
|
|
||||||
3,
|
|
||||||
true,
|
|
||||||
None,
|
|
||||||
None,
|
|
||||||
Some(5),
|
|
||||||
true,
|
|
||||||
Some(PlanetSideGUID(2913)),
|
|
||||||
None,
|
|
||||||
None,
|
|
||||||
None,
|
|
||||||
1,
|
|
||||||
2,
|
|
||||||
0
|
|
||||||
) must throwA[AssertionError]
|
|
||||||
DamageFeedbackMessage(
|
|
||||||
3,
|
|
||||||
false,
|
|
||||||
None,
|
|
||||||
Some("error"),
|
|
||||||
None,
|
|
||||||
true,
|
|
||||||
Some(PlanetSideGUID(2913)),
|
|
||||||
None,
|
|
||||||
None,
|
|
||||||
None,
|
|
||||||
1,
|
|
||||||
2,
|
|
||||||
0
|
|
||||||
) must throwA[AssertionError]
|
) must throwA[AssertionError]
|
||||||
|
|
||||||
//unk3: no parameters
|
//unk3: no parameters
|
||||||
DamageFeedbackMessage(
|
DamageFeedbackMessage(
|
||||||
3,
|
3,
|
||||||
true,
|
|
||||||
Some(PlanetSideGUID(2913)),
|
Some(PlanetSideGUID(2913)),
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
true,
|
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
1,
|
1,
|
||||||
2,
|
2
|
||||||
0
|
|
||||||
) must throwA[AssertionError]
|
) must throwA[AssertionError]
|
||||||
//unk3: two exclusive parameters
|
//unk3: two exclusive parameters
|
||||||
DamageFeedbackMessage(
|
DamageFeedbackMessage(
|
||||||
3,
|
3,
|
||||||
true,
|
|
||||||
Some(PlanetSideGUID(2913)),
|
Some(PlanetSideGUID(2913)),
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
true,
|
|
||||||
Some(PlanetSideGUID(2913)),
|
Some(PlanetSideGUID(2913)),
|
||||||
Some("error"),
|
Some("error"),
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
1,
|
1,
|
||||||
2,
|
2
|
||||||
0
|
|
||||||
) must throwA[AssertionError]
|
) must throwA[AssertionError]
|
||||||
DamageFeedbackMessage(
|
DamageFeedbackMessage(
|
||||||
3,
|
3,
|
||||||
true,
|
|
||||||
Some(PlanetSideGUID(2913)),
|
Some(PlanetSideGUID(2913)),
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
true,
|
|
||||||
Some(PlanetSideGUID(2913)),
|
Some(PlanetSideGUID(2913)),
|
||||||
None,
|
None,
|
||||||
Some(5),
|
Some(5),
|
||||||
None,
|
None,
|
||||||
1,
|
1,
|
||||||
2,
|
2
|
||||||
0
|
|
||||||
) must throwA[AssertionError]
|
) must throwA[AssertionError]
|
||||||
DamageFeedbackMessage(
|
DamageFeedbackMessage(
|
||||||
3,
|
3,
|
||||||
true,
|
|
||||||
Some(PlanetSideGUID(2913)),
|
Some(PlanetSideGUID(2913)),
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
true,
|
|
||||||
None,
|
None,
|
||||||
Some("error"),
|
Some("error"),
|
||||||
Some(5),
|
Some(5),
|
||||||
Some(1),
|
Some(1),
|
||||||
1,
|
1,
|
||||||
2,
|
2
|
||||||
0
|
|
||||||
) must throwA[AssertionError]
|
) must throwA[AssertionError]
|
||||||
//unk3: all parameters
|
//unk3: all parameters
|
||||||
DamageFeedbackMessage(
|
DamageFeedbackMessage(
|
||||||
3,
|
3,
|
||||||
true,
|
|
||||||
Some(PlanetSideGUID(2913)),
|
Some(PlanetSideGUID(2913)),
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
true,
|
|
||||||
Some(PlanetSideGUID(2913)),
|
Some(PlanetSideGUID(2913)),
|
||||||
Some("error"),
|
Some("error"),
|
||||||
Some(5),
|
Some(5),
|
||||||
None,
|
None,
|
||||||
1,
|
1,
|
||||||
2,
|
2
|
||||||
0
|
|
||||||
) must throwA[AssertionError]
|
|
||||||
//unk3: mismatched fields
|
|
||||||
DamageFeedbackMessage(
|
|
||||||
3,
|
|
||||||
true,
|
|
||||||
Some(PlanetSideGUID(2913)),
|
|
||||||
None,
|
|
||||||
None,
|
|
||||||
true,
|
|
||||||
Some(PlanetSideGUID(2913)),
|
|
||||||
None,
|
|
||||||
None,
|
|
||||||
Some(5),
|
|
||||||
1,
|
|
||||||
2,
|
|
||||||
0
|
|
||||||
) must throwA[AssertionError]
|
|
||||||
DamageFeedbackMessage(
|
|
||||||
3,
|
|
||||||
true,
|
|
||||||
Some(PlanetSideGUID(2913)),
|
|
||||||
None,
|
|
||||||
None,
|
|
||||||
true,
|
|
||||||
None,
|
|
||||||
Some("Error"),
|
|
||||||
None,
|
|
||||||
None,
|
|
||||||
1,
|
|
||||||
2,
|
|
||||||
0
|
|
||||||
) must throwA[AssertionError]
|
|
||||||
//unk3: mismatched flag for strings
|
|
||||||
DamageFeedbackMessage(
|
|
||||||
3,
|
|
||||||
true,
|
|
||||||
Some(PlanetSideGUID(2913)),
|
|
||||||
None,
|
|
||||||
None,
|
|
||||||
true,
|
|
||||||
None,
|
|
||||||
None,
|
|
||||||
Some(5),
|
|
||||||
None,
|
|
||||||
1,
|
|
||||||
2,
|
|
||||||
0
|
|
||||||
) must throwA[AssertionError]
|
|
||||||
DamageFeedbackMessage(
|
|
||||||
3,
|
|
||||||
true,
|
|
||||||
Some(PlanetSideGUID(2913)),
|
|
||||||
None,
|
|
||||||
None,
|
|
||||||
false,
|
|
||||||
None,
|
|
||||||
Some("error"),
|
|
||||||
None,
|
|
||||||
None,
|
|
||||||
1,
|
|
||||||
2,
|
|
||||||
0
|
|
||||||
) must throwA[AssertionError]
|
) must throwA[AssertionError]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue