Deployables (#230)

* functions for certifcation ui updates (that don't work)

* initialization of combat engineering deployables ui on load and certification change

* representation classes for ACE and FDU; ability to pull ACE and FDU from equipment terminals

* ammo change functionality and fire mode change functionality for ConstructionItems refactored from Tool operations and supported properly (switch between deployable options)

* zone-specific structure for keeping track of deployables; abaility to dismiss deployables from the map screen (previous functionality); local client creation of explosive-type deployables

* refactored MannedTurret into FacilityTurret and lesser traits to be used in the deployable spitfires and the OMFT's; all ACE deployables are available for placement; partial management of the construction items after the deployable is placed; boomers create boomer triggers

* Avatar-specific storage for deployables and for updating UI elements

* refactored quite a bit of code in WSA for the benefit of deployable management; refinements to deployable creation; server messages about deployable quantities; corrected the FDU encoding pattern; lots of work dedicated just to synchronizing BoomerTrigger objects

* added RemoverActor for deployables and redistributed deconstruction functionality away from WSA to new DeployableRemover; added events to facilitate activities not inheritable with this model

* refactored and distributed Deployables classes; copious amounts of testing and document-writing

* boomers now explode from trigger; support for deployables being destroyed by weapon discharge, including individual health, soure identification, and damage model; shuffled deployable classes to build different hierarchy

* sensor_shield was skipped by accident

* identified stray object in Hanish, Ishundar, and added Irkalla, Ishundar's capture console; fixed issue with Warp command and 'Irkalla'; modified building amenity setup and setup testing in Zone; players load and die properly when seated in an omft; reserve ammunition in omft properly registered

* added local service channel, capture consoles, fixed tests as much as posible

* fixed LocalService tests by booting the ServiceManager; added avatar and local tests

* a simple attempt to refactor Actor messages in a way that is acceptable to Travis CI

* making the explosive deployables vanish upon explosion; sensor health bars are now supported
This commit is contained in:
Fate-JH 2018-09-23 08:00:58 -04:00 committed by GitHub
parent 6cd18c5623
commit 5f3e7e5df8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
113 changed files with 8155 additions and 2312 deletions

View file

@ -12,15 +12,11 @@ class DeployObjectMessageTest extends Specification {
"decode" in {
PacketCoding.DecodePacket(string).require match {
case DeployObjectMessage(guid, unk1, pos, roll, pitch, yaw, unk2) =>
case DeployObjectMessage(guid, unk1, pos, orient, unk2) =>
guid mustEqual PlanetSideGUID(2932)
unk1 mustEqual 1000L
pos.x mustEqual 5769.297f
pos.y mustEqual 3192.8594f
pos.z mustEqual 97.96875f
roll mustEqual 0
pitch mustEqual 0
yaw mustEqual 63
pos mustEqual Vector3(5769.297f, 3192.8594f, 97.96875f)
orient mustEqual Vector3.z(272.8125f)
unk2 mustEqual 1L
case _ =>
ko
@ -28,7 +24,7 @@ class DeployObjectMessageTest extends Specification {
}
"encode" in {
val msg = DeployObjectMessage(PlanetSideGUID(2932), 1000L, Vector3(5769.297f, 3192.8594f, 97.96875f), 0, 0, 63, 1L)
val msg = DeployObjectMessage(PlanetSideGUID(2932), 1000L, Vector3(5769.297f, 3192.8594f, 97.96875f), Vector3.z(272.8125f), 1L)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string

View file

@ -11,10 +11,10 @@ class ObjectDeployedMessageTest extends Specification {
"decode" in {
PacketCoding.DecodePacket(string_boomer).require match {
case ObjectDeployedMessage(unk : Int, desc : String, act : DeploymentOutcome.Value, count : Long, max : Long) =>
case ObjectDeployedMessage(unk : Int, desc : String, act : DeployOutcome.Value, count : Long, max : Long) =>
unk mustEqual 0
desc mustEqual "boomer"
act mustEqual DeploymentOutcome.Success
act mustEqual DeployOutcome.Success
count mustEqual 1
max mustEqual 25
case _ =>
@ -23,7 +23,7 @@ class ObjectDeployedMessageTest extends Specification {
}
"encode" in {
val msg = ObjectDeployedMessage("boomer", DeploymentOutcome.Success, 1, 25)
val msg = ObjectDeployedMessage("boomer", DeployOutcome.Success, 1, 25)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string_boomer

View file

@ -10,6 +10,7 @@ import scodec.bits._
class TriggerEffectMessageTest extends Specification {
val string_motionalarmsensor = hex"51 970B 82 6F6E FA00C00000"
val string_boomer = hex"51 0000 93 737061776E5F6F626A6563745F656666656374 417BB2CB3B4F8E00000000"
val string_boomer_explode = hex"51 DF09 8F 6465746F6E6174655F626F6F6D6572 00"
"decode (motion alarm sensor)" in {
PacketCoding.DecodePacket(string_motionalarmsensor).require match {
@ -32,42 +33,44 @@ class TriggerEffectMessageTest extends Specification {
effect mustEqual "spawn_object_effect"
unk.isDefined mustEqual false
location.isDefined mustEqual true
location.get.pos.x mustEqual 3567.0156f
location.get.pos.y mustEqual 3278.6953f
location.get.pos.z mustEqual 114.484375f
location.get.roll mustEqual 0
location.get.pitch mustEqual 0
location.get.yaw mustEqual 0
location.get.pos mustEqual Vector3(3567.0156f, 3278.6953f, 114.484375f)
location.get.orient mustEqual Vector3(0, 0, 90)
case _ =>
ko
}
}
"decode (boomer explode)" in {
PacketCoding.DecodePacket(string_boomer_explode).require match {
case TriggerEffectMessage(guid, effect, unk, location) =>
guid mustEqual PlanetSideGUID(2527)
effect mustEqual "detonate_boomer"
unk.isDefined mustEqual false
location.isDefined mustEqual false
case _ =>
ko
}
}
"encode (motion alarm sensor)" in {
val msg = TriggerEffectMessage(
PlanetSideGUID(2967),
"on",
Some(TriggeredEffect(true, 1000L)),
None
)
val msg = TriggerEffectMessage(PlanetSideGUID(2967), "on", true, 1000L)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string_motionalarmsensor
}
"encode (boomer)" in {
val msg = TriggerEffectMessage(
PlanetSideGUID(0),
"spawn_object_effect",
None,
Some(TriggeredEffectLocation(
Vector3(3567.0156f, 3278.6953f, 114.484375f),
0, 0, 0
))
)
val msg = TriggerEffectMessage("spawn_object_effect", Vector3(3567.0156f, 3278.6953f, 114.484375f), Vector3(0, 0, 90))
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string_boomer
}
"encode (boomer explode)" in {
val msg = TriggerEffectMessage(PlanetSideGUID(2527), "detonate_boomer")
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string_boomer_explode
}
}

View file

@ -4,7 +4,7 @@ package game.objectcreate
import net.psforever.packet.PacketCoding
import net.psforever.packet.game.{ObjectCreateMessage, PlanetSideGUID}
import net.psforever.packet.game.objectcreate._
import net.psforever.types.PlanetSideEmpire
import net.psforever.types.{PlanetSideEmpire, Vector3}
import org.specs2.mutable._
import scodec.bits._
@ -22,12 +22,8 @@ class AegisShieldGeneratorDataTest extends Specification {
data.isDefined mustEqual true
data.get.isInstanceOf[AegisShieldGeneratorData] mustEqual true
val aegis = data.get.asInstanceOf[AegisShieldGeneratorData]
aegis.deploy.pos.coord.x mustEqual 3571.2266f
aegis.deploy.pos.coord.y mustEqual 3278.0938f
aegis.deploy.pos.coord.z mustEqual 114.0f
aegis.deploy.pos.orient.x mustEqual 0f
aegis.deploy.pos.orient.y mustEqual 0f
aegis.deploy.pos.orient.z mustEqual 90.0f
aegis.deploy.pos.coord mustEqual Vector3(3571.2266f, 3278.0938f, 114.0f)
aegis.deploy.pos.orient mustEqual Vector3(0, 0, 90)
aegis.deploy.faction mustEqual PlanetSideEmpire.VS
aegis.deploy.unk mustEqual 2
aegis.health mustEqual 255
@ -40,7 +36,7 @@ class AegisShieldGeneratorDataTest extends Specification {
"encode" in {
val obj = AegisShieldGeneratorData(
CommonFieldData(
PlacementData(3571.2266f, 3278.0938f, 114.0f, 0f, 0f, 90.0f),
PlacementData(Vector3(3571.2266f, 3278.0938f, 114.0f), Vector3(0, 0, 90)),
PlanetSideEmpire.VS, 2, PlanetSideGUID(2366)
),
255

View file

@ -4,7 +4,7 @@ package game.objectcreate
import net.psforever.packet.PacketCoding
import net.psforever.packet.game.{ObjectCreateMessage, PlanetSideGUID}
import net.psforever.packet.game.objectcreate._
import net.psforever.types.PlanetSideEmpire
import net.psforever.types.{PlanetSideEmpire, Vector3}
import org.specs2.mutable._
import scodec.bits._
@ -22,23 +22,19 @@ class OneMannedFieldTurretDataTest extends Specification {
data.isDefined mustEqual true
data.get.isInstanceOf[OneMannedFieldTurretData] mustEqual true
val omft = data.get.asInstanceOf[OneMannedFieldTurretData]
omft.deploy.pos.coord.x mustEqual 3567.1406f
omft.deploy.pos.coord.y mustEqual 2988.0078f
omft.deploy.pos.coord.z mustEqual 71.84375f
omft.deploy.pos.orient.x mustEqual 0f
omft.deploy.pos.orient.y mustEqual 0f
omft.deploy.pos.orient.z mustEqual 185.625f
omft.deploy.pos.coord mustEqual Vector3(3567.1406f, 2988.0078f, 71.84375f)
omft.deploy.pos.orient mustEqual Vector3(0, 0, 185.625f)
omft.deploy.faction mustEqual PlanetSideEmpire.VS
omft.deploy.unk mustEqual 2
omft.deploy.player_guid mustEqual PlanetSideGUID(2502)
omft.deploy.unk1 mustEqual 2
omft.deploy.owner_guid mustEqual PlanetSideGUID(2502)
omft.health mustEqual 255
omft.internals.isDefined mustEqual true
val internals = omft.internals.get
internals.objectClass mustEqual ObjectClass.energy_gun_vs
internals.guid mustEqual PlanetSideGUID(2615)
internals.parentSlot mustEqual 1
internals.obj.isInstanceOf[WeaponData] mustEqual true
val wep = internals.obj.asInstanceOf[WeaponData]
val internals = omft.internals.get.contents
internals.head.objectClass mustEqual ObjectClass.energy_gun_vs
internals.head.guid mustEqual PlanetSideGUID(2615)
internals.head.parentSlot mustEqual 1
internals.head.obj.isInstanceOf[WeaponData] mustEqual true
val wep = internals.head.obj.asInstanceOf[WeaponData]
wep.unk1 mustEqual 0x6
wep.unk2 mustEqual 0x8
wep.fire_mode mustEqual 0
@ -55,20 +51,16 @@ class OneMannedFieldTurretDataTest extends Specification {
"encode (orion)" in {
val obj = OneMannedFieldTurretData(
CommonFieldData(
PlacementData(3567.1406f, 2988.0078f, 71.84375f, 0f, 0f, 185.625f),
PlanetSideEmpire.VS, 2, PlanetSideGUID(2502)
SmallDeployableData(
PlacementData(Vector3(3567.1406f, 2988.0078f, 71.84375f), Vector3(0, 0, 185.625f)),
PlanetSideEmpire.VS, false, false, 2, false, false, PlanetSideGUID(2502)
),
255,
OneMannedFieldTurretData.orion(PlanetSideGUID(2615), 0x6, 0x8, PlanetSideGUID(2510), 8)
InventoryData(List(OneMannedFieldTurretData.orion(PlanetSideGUID(2615), 0x6, 0x8, PlanetSideGUID(2510), 8)))
)
val msg = ObjectCreateMessage(ObjectClass.portable_manned_turret_vs, PlanetSideGUID(2916), obj)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
val pkt_bitv = pkt.toBitVector
val ori_bitv = string_orion.toBitVector
pkt_bitv.take(189) mustEqual ori_bitv.take(189)
pkt_bitv.drop(200) mustEqual ori_bitv.drop(200)
//TODO work on OneMannedFieldTurretData to make this pass as a single stream
pkt mustEqual string_orion
}
"avenger" in {

View file

@ -4,7 +4,7 @@ package game.objectcreate
import net.psforever.packet.PacketCoding
import net.psforever.packet.game.{ObjectCreateMessage, PlanetSideGUID}
import net.psforever.packet.game.objectcreate._
import net.psforever.types.PlanetSideEmpire
import net.psforever.types.{PlanetSideEmpire, Vector3}
import org.specs2.mutable._
import scodec.bits._
@ -22,14 +22,14 @@ class SmallDeployableDataTest extends Specification {
data.isDefined mustEqual true
data.get.isInstanceOf[SmallDeployableData] mustEqual true
val boomer = data.get.asInstanceOf[SmallDeployableData]
boomer.deploy.pos.coord.x mustEqual 4704.172f
boomer.deploy.pos.coord.y mustEqual 5546.4375f
boomer.deploy.pos.coord.z mustEqual 82.234375f
boomer.deploy.pos.orient.x mustEqual 0f
boomer.deploy.pos.orient.y mustEqual 0f
boomer.deploy.pos.orient.z mustEqual 272.8125f
boomer.deploy.unk mustEqual 0
boomer.deploy.player_guid mustEqual PlanetSideGUID(4145)
boomer.pos.coord.x mustEqual 4704.172f
boomer.pos.coord.y mustEqual 5546.4375f
boomer.pos.coord.z mustEqual 82.234375f
boomer.pos.orient.x mustEqual 0f
boomer.pos.orient.y mustEqual 0f
boomer.pos.orient.z mustEqual 272.8125f
boomer.unk1 mustEqual 0
boomer.owner_guid mustEqual PlanetSideGUID(8290)
case _ =>
ko
}
@ -37,10 +37,8 @@ class SmallDeployableDataTest extends Specification {
"encode (boomer)" in {
val obj = SmallDeployableData(
CommonFieldData(
PlacementData(4704.172f, 5546.4375f, 82.234375f, 0f, 0f, 272.8125f),
PlanetSideEmpire.TR, 0, PlanetSideGUID(4145)
)
PlacementData(Vector3(4704.172f, 5546.4375f, 82.234375f), Vector3.z(272.8125f)),
PlanetSideEmpire.TR, false, false, 0, false, false, PlanetSideGUID(8290)
)
val msg = ObjectCreateMessage(ObjectClass.boomer, PlanetSideGUID(3840), obj)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector

View file

@ -3,8 +3,8 @@ package game.objectcreate
import net.psforever.packet.PacketCoding
import net.psforever.packet.game.{ObjectCreateMessage, PlanetSideGUID}
import net.psforever.packet.game.objectcreate._
import net.psforever.types.PlanetSideEmpire
import net.psforever.packet.game.objectcreate.{SmallDeployableData, _}
import net.psforever.types.{PlanetSideEmpire, Vector3}
import org.specs2.mutable._
import scodec.bits._
@ -23,16 +23,12 @@ class SmallTurretDataTest extends Specification {
data.isDefined mustEqual true
data.get.isInstanceOf[SmallTurretData] mustEqual true
val turret = data.get.asInstanceOf[SmallTurretData]
turret.deploy.pos.coord.x mustEqual 4577.7812f
turret.deploy.pos.coord.y mustEqual 5624.828f
turret.deploy.pos.coord.z mustEqual 72.046875f
turret.deploy.pos.orient.x mustEqual 0f
turret.deploy.pos.orient.y mustEqual 2.8125f
turret.deploy.pos.orient.z mustEqual 264.375f
turret.deploy.pos.coord mustEqual Vector3(4577.7812f, 5624.828f, 72.046875f)
turret.deploy.pos.orient mustEqual Vector3(0, 2.8125f, 264.375f)
turret.deploy.faction mustEqual PlanetSideEmpire.NC
turret.deploy.destroyed mustEqual true
turret.deploy.unk mustEqual 2
turret.deploy.player_guid mustEqual PlanetSideGUID(3871)
turret.deploy.unk1 mustEqual 2
turret.deploy.owner_guid mustEqual PlanetSideGUID(7742)
turret.health mustEqual 0
turret.internals.isDefined mustEqual false
case _ =>
@ -50,23 +46,19 @@ class SmallTurretDataTest extends Specification {
data.isDefined mustEqual true
data.get.isInstanceOf[SmallTurretData] mustEqual true
val turret = data.get.asInstanceOf[SmallTurretData]
turret.deploy.pos.coord.x mustEqual 4527.633f
turret.deploy.pos.coord.y mustEqual 6271.3594f
turret.deploy.pos.coord.z mustEqual 70.265625f
turret.deploy.pos.orient.x mustEqual 0f
turret.deploy.pos.orient.y mustEqual 0f
turret.deploy.pos.orient.z mustEqual 154.6875f
turret.deploy.pos.coord mustEqual Vector3(4527.633f, 6271.3594f, 70.265625f)
turret.deploy.pos.orient mustEqual Vector3(0, 0, 154.6875f)
turret.deploy.faction mustEqual PlanetSideEmpire.VS
turret.deploy.unk mustEqual 2
turret.deploy.player_guid mustEqual PlanetSideGUID(4232)
turret.deploy.unk1 mustEqual 2
turret.deploy.owner_guid mustEqual PlanetSideGUID(8208)
turret.health mustEqual 255
turret.internals.isDefined mustEqual true
val internals = turret.internals.get
internals.objectClass mustEqual ObjectClass.spitfire_weapon
internals.guid mustEqual PlanetSideGUID(3064)
internals.parentSlot mustEqual 0
internals.obj.isInstanceOf[WeaponData] mustEqual true
val wep = internals.obj.asInstanceOf[WeaponData]
val internals = turret.internals.get.contents
internals.head.objectClass mustEqual ObjectClass.spitfire_weapon
internals.head.guid mustEqual PlanetSideGUID(3064)
internals.head.parentSlot mustEqual 0
internals.head.obj.isInstanceOf[WeaponData] mustEqual true
val wep = internals.head.obj.asInstanceOf[WeaponData]
wep.unk1 mustEqual 0x6
wep.unk2 mustEqual 0x8
wep.fire_mode mustEqual 0
@ -83,37 +75,29 @@ class SmallTurretDataTest extends Specification {
"encode (spitfire, short)" in {
val obj = SmallTurretData(
CommonFieldData(
PlacementData(4577.7812f, 5624.828f, 72.046875f, 0f, 2.8125f, 264.375f),
PlanetSideEmpire.NC, true, 2, PlanetSideGUID(3871)
SmallDeployableData(
PlacementData(Vector3(4577.7812f, 5624.828f, 72.046875f), Vector3(0, 2.8125f, 264.375f)),
PlanetSideEmpire.NC, false, true, 2, false, false, PlanetSideGUID(7742)
),
255 //sets to 0
)
val msg = ObjectCreateMessage(ObjectClass.spitfire_turret, PlanetSideGUID(4208), obj)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
val pkt_bitv = pkt.toBitVector
val ori_bitv = string_spitfire_short.toBitVector
pkt_bitv.take(173) mustEqual ori_bitv.take(173)
pkt_bitv.drop(185) mustEqual ori_bitv.drop(185)
//TODO work on SmallTurretData to make this pass as a single stream
pkt mustEqual string_spitfire_short
}
"encode (spitfire)" in {
val obj = SmallTurretData(
CommonFieldData(
PlacementData(4527.633f, 6271.3594f, 70.265625f, 0f, 0f, 154.6875f),
PlanetSideEmpire.VS, 2, PlanetSideGUID(4232)
SmallDeployableData(
PlacementData(Vector3(4527.633f, 6271.3594f, 70.265625f), Vector3(0, 0, 154.6875f)),
PlanetSideEmpire.VS, false, false, 2, false, true, PlanetSideGUID(8208)
),
255,
SmallTurretData.spitfire(PlanetSideGUID(3064), 0x6, 0x8, PlanetSideGUID(3694), 8)
InventoryData(List(SmallTurretData.spitfire(PlanetSideGUID(3064), 0x6, 0x8, PlanetSideGUID(3694), 8)))
)
val msg = ObjectCreateMessage(ObjectClass.spitfire_turret, PlanetSideGUID(4265), obj)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
val pkt_bitv = pkt.toBitVector
val ori_bitv = string_spitfire.toBitVector
pkt_bitv.take(173) mustEqual ori_bitv.take(173)
pkt_bitv.drop(185) mustEqual ori_bitv.drop(185)
//TODO work on SmallTurretData to make this pass as a single stream
pkt mustEqual string_spitfire
}
}
}

View file

@ -4,7 +4,7 @@ package game.objectcreate
import net.psforever.packet.PacketCoding
import net.psforever.packet.game.{ObjectCreateMessage, PlanetSideGUID}
import net.psforever.packet.game.objectcreate._
import net.psforever.types.PlanetSideEmpire
import net.psforever.types.{PlanetSideEmpire, Vector3}
import org.specs2.mutable._
import scodec.bits._
@ -22,16 +22,11 @@ class TRAPDataTest extends Specification {
data.isDefined mustEqual true
data.get.isInstanceOf[TRAPData] mustEqual true
val trap = data.get.asInstanceOf[TRAPData]
trap.deploy.pos.coord.x mustEqual 3572.4453f
trap.deploy.pos.coord.y mustEqual 3277.9766f
trap.deploy.pos.coord.z mustEqual 114.0f
trap.deploy.pos.orient.x mustEqual 0f
trap.deploy.pos.orient.y mustEqual 0f
trap.deploy.pos.orient.z mustEqual 90.0f
trap.deploy.pos.coord mustEqual Vector3(3572.4453f, 3277.9766f, 114.0f)
trap.deploy.pos.orient mustEqual Vector3(0, 0, 90)
trap.deploy.faction mustEqual PlanetSideEmpire.VS
trap.deploy.unk mustEqual 2
trap.deploy.owner_guid mustEqual PlanetSideGUID(4748)
trap.health mustEqual 255
trap.deploy.player_guid mustEqual PlanetSideGUID(2502)
case _ =>
ko
}
@ -39,9 +34,9 @@ class TRAPDataTest extends Specification {
"encode" in {
val obj = TRAPData(
CommonFieldData(
SmallDeployableData(
PlacementData(3572.4453f, 3277.9766f, 114.0f, 0f, 0f, 90.0f),
PlanetSideEmpire.VS, 2, PlanetSideGUID(2502)
PlanetSideEmpire.VS, false, false, 2, false, true, PlanetSideGUID(4748)
),
255
)