mirror of
https://github.com/2revoemag/PSF-BotServer.git
synced 2026-07-13 15:34:42 +00:00
Yellow Ownership (#1226)
* just some tinkering and clean-up * converted DeployItem from AvatarService to LocalService; attempt at resolving missing overwhip yellow ring is complicated; vehicle ownership packet wqorks on deployables that are mountable, but is less successful on normal simple deployables * restoration of yellow ring of ownership around deployables; changes to variant of CommonFieldData transcorder used on certain deployable transcoders; static values are assigned parameter names and public variables are given types for completion * initial packet for GenericObjectAction2Message and tests; repaired transcoders and tests for TRAP and small turrets * force redraw of the whole boomer to assert reassignment of ownership; it's heavy-handed but it works * deployable ownership should be asserted during both re-zoning and revival; refactoring of code in ZoningOperations
This commit is contained in:
parent
d2d7c2e09b
commit
9708bf9beb
49 changed files with 593 additions and 502 deletions
|
|
@ -130,29 +130,6 @@ class EquipmentInHandTest extends ActorTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class DeployItemTest extends ActorTest {
|
|
||||||
ServiceManager.boot(system)
|
|
||||||
val service = system.actorOf(Props(classOf[AvatarService], Zone.Nowhere), "deploy-item-test-service")
|
|
||||||
val objDef = GlobalDefinitions.motionalarmsensor
|
|
||||||
val obj = new SensorDeployable(objDef)
|
|
||||||
obj.Position = Vector3(1, 2, 3)
|
|
||||||
obj.Orientation = Vector3(4, 5, 6)
|
|
||||||
obj.GUID = PlanetSideGUID(40)
|
|
||||||
val pkt = ObjectCreateMessage(
|
|
||||||
objDef.ObjectId,
|
|
||||||
obj.GUID,
|
|
||||||
objDef.Packet.ConstructorData(obj).get
|
|
||||||
)
|
|
||||||
|
|
||||||
"AvatarService" should {
|
|
||||||
"pass DeployItem" in {
|
|
||||||
service ! Service.Join("test")
|
|
||||||
service ! AvatarServiceMessage("test", AvatarAction.DeployItem(PlanetSideGUID(10), obj))
|
|
||||||
expectMsg(AvatarServiceResponse("/test/Avatar", PlanetSideGUID(10), AvatarResponse.DropItem(pkt)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class DroptItemTest extends ActorTest {
|
class DroptItemTest extends ActorTest {
|
||||||
ServiceManager.boot(system)
|
ServiceManager.boot(system)
|
||||||
val service = system.actorOf(Props(classOf[AvatarService], Zone.Nowhere), "release-test-service")
|
val service = system.actorOf(Props(classOf[AvatarService], Zone.Nowhere), "release-test-service")
|
||||||
|
|
|
||||||
|
|
@ -563,7 +563,7 @@ class GeneralOperations(
|
||||||
* @param unk2 na
|
* @param unk2 na
|
||||||
*/
|
*/
|
||||||
def hackObject(targetGuid: PlanetSideGUID, unk1: Long, unk2: HackState7): Unit = {
|
def hackObject(targetGuid: PlanetSideGUID, unk1: Long, unk2: HackState7): Unit = {
|
||||||
sendResponse(HackMessage(HackState1.Unk0, targetGuid, player_guid=Service.defaultPlayerGUID, progress=100, unk1, HackState.Hacked, unk2))
|
sendResponse(HackMessage(HackState1.Unk0, targetGuid, player_guid=Service.defaultPlayerGUID, progress=100, unk1.toFloat, HackState.Hacked, unk2))
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -8,8 +8,9 @@ import akka.pattern.ask
|
||||||
import akka.util.Timeout
|
import akka.util.Timeout
|
||||||
import net.psforever.actors.session.spectator.SpectatorMode
|
import net.psforever.actors.session.spectator.SpectatorMode
|
||||||
import net.psforever.login.WorldSession
|
import net.psforever.login.WorldSession
|
||||||
import net.psforever.objects.avatar.BattleRank
|
import net.psforever.objects.avatar.{BattleRank, DeployableToolbox}
|
||||||
import net.psforever.objects.avatar.scoring.{CampaignStatistics, ScoreCard, SessionStatistics}
|
import net.psforever.objects.avatar.scoring.{CampaignStatistics, ScoreCard, SessionStatistics}
|
||||||
|
import net.psforever.objects.definition.converter.OCM
|
||||||
import net.psforever.objects.inventory.InventoryItem
|
import net.psforever.objects.inventory.InventoryItem
|
||||||
import net.psforever.objects.serverobject.interior.Sidedness
|
import net.psforever.objects.serverobject.interior.Sidedness
|
||||||
import net.psforever.objects.serverobject.mount.Seat
|
import net.psforever.objects.serverobject.mount.Seat
|
||||||
|
|
@ -28,7 +29,7 @@ import scala.util.Success
|
||||||
//
|
//
|
||||||
import net.psforever.actors.session.{AvatarActor, SessionActor}
|
import net.psforever.actors.session.{AvatarActor, SessionActor}
|
||||||
import net.psforever.login.WorldSession.RemoveOldEquipmentFromInventory
|
import net.psforever.login.WorldSession.RemoveOldEquipmentFromInventory
|
||||||
import net.psforever.objects.avatar.{Avatar, DeployableToolbox}
|
import net.psforever.objects.avatar.Avatar
|
||||||
import net.psforever.objects.avatar.{Award, AwardCategory, PlayerControl, Shortcut => AvatarShortcut}
|
import net.psforever.objects.avatar.{Award, AwardCategory, PlayerControl, Shortcut => AvatarShortcut}
|
||||||
import net.psforever.objects.ce.{Deployable, DeployableCategory, DeployedItem, TelepadLike}
|
import net.psforever.objects.ce.{Deployable, DeployableCategory, DeployedItem, TelepadLike}
|
||||||
import net.psforever.objects.definition.SpecialExoSuitDefinition
|
import net.psforever.objects.definition.SpecialExoSuitDefinition
|
||||||
|
|
@ -215,104 +216,13 @@ class ZoningOperations(
|
||||||
sendResponse(ReplicationStreamMessage(5, Some(6), Vector.empty)) //clear squad list
|
sendResponse(ReplicationStreamMessage(5, Some(6), Vector.empty)) //clear squad list
|
||||||
sendResponse(PlanetsideAttributeMessage(PlanetSideGUID(0), 112, 0)) // disable festive backpacks
|
sendResponse(PlanetsideAttributeMessage(PlanetSideGUID(0), 112, 0)) // disable festive backpacks
|
||||||
|
|
||||||
//find and reclaim own deployables, if any
|
val deployables = continent.DeployableList
|
||||||
val foundDeployables = continent.DeployableList.filter {
|
reclaimOurDeployables(deployables, name, manageDeployablesWith(player.GUID, avatar.deployables))
|
||||||
case _: BoomerDeployable => false //if we do find boomers for any reason, ignore them
|
drawDeployableIconsOnMap(
|
||||||
case dobj => dobj.OwnerName.contains(player.Name) && dobj.Health > 0
|
depictDeployables(deployables).filter(_.Faction == faction)
|
||||||
}
|
|
||||||
foundDeployables.collect {
|
|
||||||
case obj if avatar.deployables.AddOverLimit(obj) =>
|
|
||||||
obj.Actor ! Deployable.Ownership(player)
|
|
||||||
}
|
|
||||||
//render deployable objects
|
|
||||||
val (turrets, normal) = continent.DeployableList.partition(obj =>
|
|
||||||
DeployableToolbox.UnifiedType(obj.Definition.Item) == DeployedItem.portable_manned_turret
|
|
||||||
)
|
)
|
||||||
normal.foreach(obj => {
|
|
||||||
val definition = obj.Definition
|
|
||||||
sendResponse(
|
|
||||||
ObjectCreateMessage(
|
|
||||||
definition.ObjectId,
|
|
||||||
obj.GUID,
|
|
||||||
definition.Packet.ConstructorData(obj).get
|
|
||||||
)
|
|
||||||
)
|
|
||||||
})
|
|
||||||
turrets.foreach(obj => {
|
|
||||||
val objGUID = obj.GUID
|
|
||||||
val definition = obj.Definition
|
|
||||||
sendResponse(
|
|
||||||
ObjectCreateMessage(
|
|
||||||
definition.ObjectId,
|
|
||||||
objGUID,
|
|
||||||
definition.Packet.ConstructorData(obj).get
|
|
||||||
)
|
|
||||||
)
|
|
||||||
//seated players
|
|
||||||
obj
|
|
||||||
.asInstanceOf[Mountable]
|
|
||||||
.Seats
|
|
||||||
.values
|
|
||||||
.map(_.occupant)
|
|
||||||
.collect {
|
|
||||||
case Some(occupant) =>
|
|
||||||
if (occupant.isAlive) {
|
|
||||||
val targetDefinition = occupant.avatar.definition
|
|
||||||
sendResponse(
|
|
||||||
ObjectCreateMessage(
|
|
||||||
targetDefinition.ObjectId,
|
|
||||||
occupant.GUID,
|
|
||||||
ObjectCreateMessageParent(objGUID, 0),
|
|
||||||
targetDefinition.Packet.ConstructorData(occupant).get
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//auto turret behavior
|
|
||||||
(obj match {
|
|
||||||
case turret: AutomatedTurret with JammableUnit => turret.Target
|
|
||||||
case _ => None
|
|
||||||
}).collect {
|
|
||||||
target =>
|
|
||||||
val guid = obj.GUID
|
|
||||||
val turret = obj.asInstanceOf[AutomatedTurret]
|
|
||||||
sendResponse(ObjectDetectedMessage(guid, guid, 0, List(target.GUID)))
|
|
||||||
if (!obj.asInstanceOf[JammableUnit].Jammed) {
|
|
||||||
sendResponse(ChangeFireStateMessage_Start(turret.Weapons.values.head.Equipment.get.GUID))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
//sensor animation
|
|
||||||
normal
|
|
||||||
.filter(obj =>
|
|
||||||
obj.Definition.DeployCategory == DeployableCategory.Sensors &&
|
|
||||||
!obj.Destroyed &&
|
|
||||||
(obj match {
|
|
||||||
case jObj: JammableUnit => !jObj.Jammed
|
|
||||||
case _ => true
|
|
||||||
})
|
|
||||||
)
|
|
||||||
.foreach(obj => {
|
|
||||||
sendResponse(TriggerEffectMessage(obj.GUID, "on", unk1=true, 1000))
|
|
||||||
})
|
|
||||||
//update the health of our faction's deployables (if necessary)
|
|
||||||
//draw our faction's deployables on the map
|
|
||||||
continent.DeployableList
|
|
||||||
.filter(obj => obj.Faction == faction && !obj.Destroyed)
|
|
||||||
.foreach(obj => {
|
|
||||||
if (obj.Health != obj.DefaultHealth) {
|
|
||||||
sendResponse(PlanetsideAttributeMessage(obj.GUID, 0, obj.Health))
|
|
||||||
}
|
|
||||||
val deployInfo = DeployableInfo(
|
|
||||||
obj.GUID,
|
|
||||||
Deployable.Icon(obj.Definition.Item),
|
|
||||||
obj.Position,
|
|
||||||
obj.OwnerGuid.getOrElse(PlanetSideGUID(0))
|
|
||||||
)
|
|
||||||
sendResponse(DeployableObjectsInfoMessage(DeploymentAction.Build, deployInfo))
|
|
||||||
})
|
|
||||||
//render Equipment that was dropped into zone before the player arrived
|
//render Equipment that was dropped into zone before the player arrived
|
||||||
continent.EquipmentOnGround.foreach(item => {
|
continent.EquipmentOnGround.foreach { item =>
|
||||||
val definition = item.Definition
|
val definition = item.Definition
|
||||||
sendResponse(
|
sendResponse(
|
||||||
ObjectCreateMessage(
|
ObjectCreateMessage(
|
||||||
|
|
@ -324,26 +234,19 @@ class ZoningOperations(
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
})
|
}
|
||||||
//load active players in zone (excepting players who are seated or players who are us)
|
//load active players in zone (excepting players who are seated or players who are us)
|
||||||
val live = continent.LivePlayers
|
val live = continent.LivePlayers
|
||||||
live
|
live
|
||||||
.filterNot(tplayer => {
|
.filterNot { tplayer =>
|
||||||
tplayer.GUID == player.GUID || tplayer.VehicleSeated.nonEmpty
|
tplayer.GUID == player.GUID || tplayer.VehicleSeated.nonEmpty
|
||||||
})
|
}
|
||||||
.foreach(targetPlayer => {
|
.foreach { targetPlayer =>
|
||||||
val targetDefinition = player.avatar.definition
|
sendResponse(OCM.apply(targetPlayer))
|
||||||
sendResponse(
|
|
||||||
ObjectCreateMessage(
|
|
||||||
targetDefinition.ObjectId,
|
|
||||||
targetPlayer.GUID,
|
|
||||||
targetDefinition.Packet.ConstructorData(targetPlayer).get
|
|
||||||
)
|
|
||||||
)
|
|
||||||
if (targetPlayer.UsingSpecial == SpecialExoSuitDefinition.Mode.Anchored) {
|
if (targetPlayer.UsingSpecial == SpecialExoSuitDefinition.Mode.Anchored) {
|
||||||
sendResponse(PlanetsideAttributeMessage(targetPlayer.GUID, 19, 1))
|
sendResponse(PlanetsideAttributeMessage(targetPlayer.GUID, 19, 1))
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
//load corpses in zone
|
//load corpses in zone
|
||||||
continent.Corpses.foreach {
|
continent.Corpses.foreach {
|
||||||
spawn.DepictPlayerAsCorpse
|
spawn.DepictPlayerAsCorpse
|
||||||
|
|
@ -376,10 +279,7 @@ class ZoningOperations(
|
||||||
//active vehicles (and some wreckage)
|
//active vehicles (and some wreckage)
|
||||||
vehicles.foreach { vehicle =>
|
vehicles.foreach { vehicle =>
|
||||||
val vguid = vehicle.GUID
|
val vguid = vehicle.GUID
|
||||||
val vdefinition = vehicle.Definition
|
sendResponse(OCM.apply(vehicle))
|
||||||
sendResponse(
|
|
||||||
ObjectCreateMessage(vdefinition.ObjectId, vguid, vdefinition.Packet.ConstructorData(vehicle).get)
|
|
||||||
)
|
|
||||||
//occupants other than driver (with exceptions)
|
//occupants other than driver (with exceptions)
|
||||||
vehicle.Seats
|
vehicle.Seats
|
||||||
.filter {
|
.filter {
|
||||||
|
|
@ -393,15 +293,10 @@ class ZoningOperations(
|
||||||
}
|
}
|
||||||
.foreach {
|
.foreach {
|
||||||
case (index, seat) =>
|
case (index, seat) =>
|
||||||
val targetPlayer = seat.occupant.get
|
|
||||||
val targetDefiniton = targetPlayer.avatar.definition
|
|
||||||
sendResponse(
|
sendResponse(
|
||||||
ObjectCreateMessage(
|
OCM.apply(seat.occupant.get)
|
||||||
targetDefiniton.ObjectId,
|
.asInstanceOf[ObjectCreateMessage]
|
||||||
targetPlayer.GUID,
|
.copy(parentInfo = Some(ObjectCreateMessageParent(vguid, index)))
|
||||||
ObjectCreateMessageParent(vguid, index),
|
|
||||||
targetDefiniton.Packet.ConstructorData(targetPlayer).get
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
vehicle.SubsystemMessages().foreach { sendResponse }
|
vehicle.SubsystemMessages().foreach { sendResponse }
|
||||||
|
|
@ -411,8 +306,8 @@ class ZoningOperations(
|
||||||
Vehicles.ReloadAccessPermissions(vehicle, player.Name)
|
Vehicles.ReloadAccessPermissions(vehicle, player.Name)
|
||||||
}
|
}
|
||||||
//our vehicle would have already been loaded; see NewPlayerLoaded/AvatarCreate
|
//our vehicle would have already been loaded; see NewPlayerLoaded/AvatarCreate
|
||||||
usedVehicle.headOption match {
|
usedVehicle.headOption.collect {
|
||||||
case Some(vehicle) =>
|
case vehicle =>
|
||||||
//subsystems
|
//subsystems
|
||||||
vehicle.Actor ! Vehicle.UpdateSubsystemStates(player.Name, Some(false))
|
vehicle.Actor ! Vehicle.UpdateSubsystemStates(player.Name, Some(false))
|
||||||
//depict any other passengers already in this zone
|
//depict any other passengers already in this zone
|
||||||
|
|
@ -430,15 +325,10 @@ class ZoningOperations(
|
||||||
}
|
}
|
||||||
.foreach {
|
.foreach {
|
||||||
case (index, seat) =>
|
case (index, seat) =>
|
||||||
val targetPlayer = seat.occupant.get
|
|
||||||
val targetDefinition = targetPlayer.avatar.definition
|
|
||||||
sendResponse(
|
sendResponse(
|
||||||
ObjectCreateMessage(
|
OCM.apply(seat.occupant.get)
|
||||||
targetDefinition.ObjectId,
|
.asInstanceOf[ObjectCreateMessage]
|
||||||
targetPlayer.GUID,
|
.copy(parentInfo = Some(ObjectCreateMessageParent(vguid, index)))
|
||||||
ObjectCreateMessageParent(vguid, index),
|
|
||||||
targetDefinition.Packet.ConstructorData(targetPlayer).get
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
//since we would have only subscribed recently, we need to reload mount access states
|
//since we would have only subscribed recently, we need to reload mount access states
|
||||||
|
|
@ -449,10 +339,9 @@ class ZoningOperations(
|
||||||
if (vehicle.Shields > 0) {
|
if (vehicle.Shields > 0) {
|
||||||
sendResponse(PlanetsideAttributeMessage(vguid, vehicle.Definition.shieldUiAttribute, vehicle.Shields))
|
sendResponse(PlanetsideAttributeMessage(vguid, vehicle.Definition.shieldUiAttribute, vehicle.Shields))
|
||||||
}
|
}
|
||||||
case _ => () //no vehicle
|
|
||||||
}
|
}
|
||||||
//vehicle wreckages
|
//vehicle wreckages
|
||||||
wreckages.foreach(vehicle => {
|
wreckages.foreach { vehicle =>
|
||||||
sendResponse(
|
sendResponse(
|
||||||
ObjectCreateMessage(
|
ObjectCreateMessage(
|
||||||
vehicle.Definition.DestroyedModel.get.id,
|
vehicle.Definition.DestroyedModel.get.id,
|
||||||
|
|
@ -460,17 +349,14 @@ class ZoningOperations(
|
||||||
DestroyedVehicleConverter.converter.ConstructorData(vehicle).get
|
DestroyedVehicleConverter.converter.ConstructorData(vehicle).get
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
})
|
}
|
||||||
//cargo occupants (including our own vehicle as cargo)
|
//cargo occupants (including our own vehicle as cargo)
|
||||||
allActiveVehicles.collect {
|
allActiveVehicles.collect {
|
||||||
case vehicle if vehicle.CargoHolds.nonEmpty =>
|
case vehicle if vehicle.CargoHolds.nonEmpty =>
|
||||||
vehicle.CargoHolds.collect {
|
vehicle.CargoHolds.collect {
|
||||||
case (_index, hold: Cargo) if hold.isOccupied =>
|
case (_index, hold: Cargo) if hold.isOccupied =>
|
||||||
CarrierBehavior.CargoMountBehaviorForAll(
|
//CargoMountBehaviorForUs can fail to attach the cargo vehicle on some clients
|
||||||
vehicle,
|
CarrierBehavior.CargoMountBehaviorForAll(vehicle, hold.occupant.get, _index)
|
||||||
hold.occupant.get,
|
|
||||||
_index
|
|
||||||
) //CargoMountBehaviorForUs can fail to attach the cargo vehicle on some clients
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//special deploy states
|
//special deploy states
|
||||||
|
|
@ -492,8 +378,8 @@ class ZoningOperations(
|
||||||
}
|
}
|
||||||
deployedVehicles.filter(_.Definition == GlobalDefinitions.router).foreach { obj =>
|
deployedVehicles.filter(_.Definition == GlobalDefinitions.router).foreach { obj =>
|
||||||
//the router won't work if it doesn't completely deploy
|
//the router won't work if it doesn't completely deploy
|
||||||
sendResponse(DeployRequestMessage(player.GUID, obj.GUID, DriveState.Deploying, 0, unk3=false, Vector3.Zero))
|
sendResponse(DeployRequestMessage(player.GUID, obj.GUID, DriveState.Deploying, 0, unk3 = false, Vector3.Zero))
|
||||||
sendResponse(DeployRequestMessage(player.GUID, obj.GUID, DriveState.Deployed, 0, unk3=false, Vector3.Zero))
|
sendResponse(DeployRequestMessage(player.GUID, obj.GUID, DriveState.Deployed, 0, unk3 = false, Vector3.Zero))
|
||||||
sessionLogic.general.toggleTeleportSystem(obj, TelepadLike.AppraiseTeleportationSystem(obj, continent))
|
sessionLogic.general.toggleTeleportSystem(obj, TelepadLike.AppraiseTeleportationSystem(obj, continent))
|
||||||
}
|
}
|
||||||
ServiceManager.serviceManager
|
ServiceManager.serviceManager
|
||||||
|
|
@ -504,41 +390,30 @@ class ZoningOperations(
|
||||||
case _ =>
|
case _ =>
|
||||||
}
|
}
|
||||||
//implant terminals
|
//implant terminals
|
||||||
continent.map.terminalToInterface.foreach({
|
continent.map.terminalToInterface.foreach {
|
||||||
case (terminal_guid, interface_guid) =>
|
case (terminal_guid, interface_guid) =>
|
||||||
val parent_guid = PlanetSideGUID(terminal_guid)
|
val parent_guid = PlanetSideGUID(terminal_guid)
|
||||||
continent.GUID(interface_guid) match {
|
continent.GUID(interface_guid).collect {
|
||||||
case Some(obj: Terminal) =>
|
case obj: Terminal =>
|
||||||
val objDef = obj.Definition
|
|
||||||
sendResponse(
|
sendResponse(
|
||||||
ObjectCreateMessage(
|
OCM.apply(obj)
|
||||||
objDef.ObjectId,
|
.asInstanceOf[ObjectCreateMessage]
|
||||||
PlanetSideGUID(interface_guid),
|
.copy(parentInfo = Some(ObjectCreateMessageParent(parent_guid, 1)))
|
||||||
ObjectCreateMessageParent(parent_guid, 1),
|
|
||||||
objDef.Packet.ConstructorData(obj).get
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
case _ => ()
|
|
||||||
}
|
}
|
||||||
//mount terminal occupants
|
//mount terminal occupants
|
||||||
continent.GUID(terminal_guid) match {
|
continent.GUID(terminal_guid).collect {
|
||||||
case Some(obj: Mountable) =>
|
case obj: Mountable =>
|
||||||
obj.Seats(0).occupant match {
|
obj.Seats(0).occupant.collect {
|
||||||
case Some(targetPlayer: Player) =>
|
case occupant: Player =>
|
||||||
val targetDefinition = targetPlayer.avatar.definition
|
|
||||||
sendResponse(
|
sendResponse(
|
||||||
ObjectCreateMessage(
|
OCM.apply(occupant)
|
||||||
targetDefinition.ObjectId,
|
.asInstanceOf[ObjectCreateMessage]
|
||||||
targetPlayer.GUID,
|
.copy(parentInfo = Some(ObjectCreateMessageParent(parent_guid, 0)))
|
||||||
ObjectCreateMessageParent(parent_guid, 0),
|
|
||||||
targetDefinition.Packet.ConstructorData(targetPlayer).get
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
case _ => ()
|
|
||||||
}
|
}
|
||||||
case _ => ()
|
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
//facility turrets
|
//facility turrets
|
||||||
continent.map.turretToWeapon
|
continent.map.turretToWeapon
|
||||||
.map { case (turret_guid: Int, _) => continent.GUID(turret_guid) }
|
.map { case (turret_guid: Int, _) => continent.GUID(turret_guid) }
|
||||||
|
|
@ -549,14 +424,10 @@ class ZoningOperations(
|
||||||
if (!turret.isUpgrading) {
|
if (!turret.isUpgrading) {
|
||||||
turret.ControlledWeapon(wepNumber = 1).foreach {
|
turret.ControlledWeapon(wepNumber = 1).foreach {
|
||||||
case obj: Tool =>
|
case obj: Tool =>
|
||||||
val objDef = obj.Definition
|
|
||||||
sendResponse(
|
sendResponse(
|
||||||
ObjectCreateMessage(
|
OCM.apply(obj)
|
||||||
objDef.ObjectId,
|
.asInstanceOf[ObjectCreateMessage]
|
||||||
obj.GUID,
|
.copy(parentInfo = Some(ObjectCreateMessageParent(pguid, 1)))
|
||||||
ObjectCreateMessageParent(pguid, 1),
|
|
||||||
objDef.Packet.ConstructorData(obj).get
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
case _ => ()
|
case _ => ()
|
||||||
}
|
}
|
||||||
|
|
@ -564,38 +435,19 @@ class ZoningOperations(
|
||||||
//reserved ammunition?
|
//reserved ammunition?
|
||||||
//TODO need to register if it exists
|
//TODO need to register if it exists
|
||||||
//mount turret occupant
|
//mount turret occupant
|
||||||
turret.Seats(0).occupant match {
|
turret.Seats(0).occupant.collect {
|
||||||
case Some(targetPlayer: Player) =>
|
case occupant: Player =>
|
||||||
val targetDefinition = targetPlayer.avatar.definition
|
|
||||||
sendResponse(
|
sendResponse(
|
||||||
ObjectCreateMessage(
|
OCM.apply(occupant)
|
||||||
targetDefinition.ObjectId,
|
.asInstanceOf[ObjectCreateMessage]
|
||||||
targetPlayer.GUID,
|
.copy(parentInfo = Some(ObjectCreateMessageParent(pguid, 0)))
|
||||||
ObjectCreateMessageParent(pguid, 0),
|
|
||||||
targetDefinition.Packet.ConstructorData(targetPlayer).get
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
case _ => ()
|
|
||||||
}
|
|
||||||
turret.Target.collect {
|
|
||||||
target =>
|
|
||||||
val guid = turret.GUID
|
|
||||||
sendResponse(ObjectDetectedMessage(guid, guid, 0, List(target.GUID)))
|
|
||||||
if (!turret.Jammed) {
|
|
||||||
sendResponse(ChangeFireStateMessage_Start(turret.Weapons.values.head.Equipment.get.GUID))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
triggerAutomatedTurretFire(turret)
|
||||||
}
|
}
|
||||||
//remote projectiles and radiation clouds
|
//remote projectiles and radiation clouds
|
||||||
continent.Projectiles.foreach { projectile =>
|
continent.Projectiles.foreach { projectile =>
|
||||||
val definition = projectile.Definition
|
sendResponse(OCM.apply(projectile))
|
||||||
sendResponse(
|
|
||||||
ObjectCreateMessage(
|
|
||||||
definition.ObjectId,
|
|
||||||
projectile.GUID,
|
|
||||||
definition.Packet.ConstructorData(projectile).get
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
//spawn point update request
|
//spawn point update request
|
||||||
continent.VehicleEvents ! VehicleServiceMessage(
|
continent.VehicleEvents ! VehicleServiceMessage(
|
||||||
|
|
@ -1166,14 +1018,7 @@ class ZoningOperations(
|
||||||
// sync capture flags
|
// sync capture flags
|
||||||
case llu: CaptureFlag =>
|
case llu: CaptureFlag =>
|
||||||
// Create LLU
|
// Create LLU
|
||||||
sendResponse(
|
sendResponse(OCM.apply(llu))
|
||||||
ObjectCreateMessage(
|
|
||||||
llu.Definition.ObjectId,
|
|
||||||
llu.GUID,
|
|
||||||
llu.Definition.Packet.ConstructorData(llu).get
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
// Attach it to a player if it has a carrier
|
// Attach it to a player if it has a carrier
|
||||||
if (llu.Carrier.nonEmpty) {
|
if (llu.Carrier.nonEmpty) {
|
||||||
continent.LocalEvents ! LocalServiceMessage(
|
continent.LocalEvents ! LocalServiceMessage(
|
||||||
|
|
@ -1755,6 +1600,188 @@ class ZoningOperations(
|
||||||
*/
|
*/
|
||||||
def NormalKeepAlive(): Unit = {}
|
def NormalKeepAlive(): Unit = {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find all deployables that internally keep track of a player's name as its owner
|
||||||
|
* and change the GUID associated with that owner (reclaim it).
|
||||||
|
* @param deployables list of deployables
|
||||||
|
* @param name owner name
|
||||||
|
* @param reclamationStrategy what happens to deployables to re-assign ownership
|
||||||
|
* @return the list of deployables whose owenrship has been re-assigned
|
||||||
|
*/
|
||||||
|
def reclaimOurDeployables(
|
||||||
|
deployables: List[Deployable],
|
||||||
|
name: String,
|
||||||
|
reclamationStrategy: Deployable => Option[Deployable]
|
||||||
|
): List[Deployable] = {
|
||||||
|
deployables
|
||||||
|
.filter {
|
||||||
|
case _: BoomerDeployable => false //always ignore
|
||||||
|
case obj => obj.OwnerName.contains(name) && !obj.Destroyed && obj.Health > 0
|
||||||
|
}
|
||||||
|
.flatMap(reclamationStrategy)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If the deployable was added to a management collection, reassign its internal owner GUID.
|
||||||
|
* Hence, it can fail.
|
||||||
|
* @param toGuid anticipated ownership GUID
|
||||||
|
* @param managedDeployables collection for logically organizing deployables
|
||||||
|
* @param obj deployable designated for ownership
|
||||||
|
* @return the deployable, if it was capable of being managed and ownership was re-assigned
|
||||||
|
*/
|
||||||
|
def manageDeployablesWith(toGuid: PlanetSideGUID, managedDeployables: DeployableToolbox)(obj: Deployable): Option[Deployable] = {
|
||||||
|
if (managedDeployables.AddOverLimit(obj)) {
|
||||||
|
reassignDeployablesTo(toGuid)(obj)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reassign the internal owner GUID on this deployable.
|
||||||
|
* @param toGuid anticipated ownership GUID
|
||||||
|
* @param obj deployable designated for ownership
|
||||||
|
* @return the deployable, but now assigned to the GUID
|
||||||
|
*/
|
||||||
|
def reassignDeployablesTo(toGuid: PlanetSideGUID)(obj: Deployable): Option[Deployable] = {
|
||||||
|
obj.OwnerGuid = toGuid
|
||||||
|
Some(obj)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render and animate all provided deployables.
|
||||||
|
* Animation includes occupants for mountable deployables and ongoing behaviors for automated deployables.
|
||||||
|
* @param deployables list of deployables
|
||||||
|
* @return list of working deployables
|
||||||
|
* @see `OCM.apply`
|
||||||
|
*/
|
||||||
|
def depictDeployables(deployables: List[Deployable]): List[Deployable] = {
|
||||||
|
val (smallTurrets, largeTurrets, sensors, normal, brokenThings) = {
|
||||||
|
val (broken, working) = deployables.partition { obj =>
|
||||||
|
obj.Destroyed || obj.Health == 0 || (obj match {
|
||||||
|
case jammable: JammableUnit => jammable.Jammed
|
||||||
|
case _ => false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
val (small, remainder1) = working.partition { obj => obj.Definition.DeployCategory == DeployableCategory.SmallTurrets }
|
||||||
|
val (large, remainder2) = remainder1.partition { obj => obj.Definition.DeployCategory == DeployableCategory.FieldTurrets }
|
||||||
|
val (sensor, remainder3) = remainder2.partition { obj => obj.Definition.DeployCategory == DeployableCategory.Sensors }
|
||||||
|
(small, large, sensor, remainder3, broken)
|
||||||
|
}
|
||||||
|
val miscThings = normal ++ sensors ++ smallTurrets
|
||||||
|
(brokenThings ++ miscThings).foreach { obj =>
|
||||||
|
sendResponse(OCM.apply(obj))
|
||||||
|
}
|
||||||
|
largeTurrets.foreach { obj =>
|
||||||
|
sendResponse(OCM.apply(obj))
|
||||||
|
//seated players
|
||||||
|
obj
|
||||||
|
.asInstanceOf[Mountable]
|
||||||
|
.Seats
|
||||||
|
.values
|
||||||
|
.map(_.occupant)
|
||||||
|
.collect {
|
||||||
|
case Some(occupant) if occupant.isAlive =>
|
||||||
|
sendResponse(
|
||||||
|
OCM.apply(occupant)
|
||||||
|
.asInstanceOf[ObjectCreateMessage]
|
||||||
|
.copy(parentInfo = Some(ObjectCreateMessageParent(obj.GUID, 0)))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
triggerAutomatedTurretFire(smallTurrets)
|
||||||
|
triggerSensorDeployables(sensors)
|
||||||
|
miscThings ++ largeTurrets
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render and animate all provided deployables.
|
||||||
|
* Animation includes ongoing behaviors for automated deployables.
|
||||||
|
* @param deployables list of deployables
|
||||||
|
* @return list of working deployables
|
||||||
|
* @see `OCM.apply`
|
||||||
|
*/
|
||||||
|
def depictDeployablesUponRevival(deployables: List[Deployable]): List[Deployable] = {
|
||||||
|
val (smallTurrets, sensors, normal) = {
|
||||||
|
val (_, working) = deployables.partition { obj =>
|
||||||
|
obj.Destroyed || obj.Health == 0 || (obj match {
|
||||||
|
case jammable: JammableUnit => jammable.Jammed
|
||||||
|
case _ => false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
val (small, remainder1) = working.partition { obj => obj.Definition.DeployCategory == DeployableCategory.SmallTurrets }
|
||||||
|
val (sensor, remainder2) = remainder1.partition { obj => obj.Definition.DeployCategory == DeployableCategory.Sensors }
|
||||||
|
(small, sensor, remainder2)
|
||||||
|
}
|
||||||
|
val miscThings = normal ++ sensors ++ smallTurrets
|
||||||
|
miscThings.foreach { obj =>
|
||||||
|
sendResponse(OCM.apply(obj))
|
||||||
|
}
|
||||||
|
triggerAutomatedTurretFire(smallTurrets)
|
||||||
|
triggerSensorDeployables(sensors)
|
||||||
|
miscThings
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Treat the deployables as sensor-types and provide appropriate animation.
|
||||||
|
* This animation is the glowing halo-ing effect on its sensor bulb.
|
||||||
|
* @param sensors list of deployables
|
||||||
|
* @see `TriggerEffectMessage`
|
||||||
|
*/
|
||||||
|
def triggerSensorDeployables(sensors: List[Deployable]): Unit = {
|
||||||
|
sensors.foreach { obj =>
|
||||||
|
sendResponse(TriggerEffectMessage(obj.GUID, effect = "on", unk1 = true, unk2 = 1000))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Treat the deployables as small turret-types and provide appropriate animation.
|
||||||
|
* This animation is related to its automation - tracking and shooting.
|
||||||
|
* @param turrets list of deployables
|
||||||
|
*/
|
||||||
|
def triggerAutomatedTurretFire(turrets: List[Deployable]): Unit = {
|
||||||
|
turrets.collect { case turret: AutomatedTurret =>
|
||||||
|
triggerAutomatedTurretFire(turret)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Provide appropriate animation to the small turret deployable.
|
||||||
|
* This animation is related to its automation - tracking and shooting.
|
||||||
|
* @param turret small turret deployable
|
||||||
|
* @see `ChangeFireStateMessage_Start`
|
||||||
|
* @see `ObjectDetectedMessage`
|
||||||
|
*/
|
||||||
|
def triggerAutomatedTurretFire(turret: AutomatedTurret): Unit = {
|
||||||
|
turret.Target.foreach { target =>
|
||||||
|
val guid = turret.GUID
|
||||||
|
sendResponse(ObjectDetectedMessage(guid, guid, 0, List(target.GUID)))
|
||||||
|
sendResponse(ChangeFireStateMessage_Start(turret.Weapons.values.head.Equipment.get.GUID))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Draw or redraw deployment map icons related to deployable presence and deployable management (if the owner).
|
||||||
|
* Assert deployable health as a precaution.
|
||||||
|
* @param deployables list of deployables
|
||||||
|
* @see `DeployableObjectsInfoMessage`
|
||||||
|
*/
|
||||||
|
def drawDeployableIconsOnMap(deployables: List[Deployable]): Unit = {
|
||||||
|
deployables
|
||||||
|
.foreach { obj =>
|
||||||
|
val guid = obj.GUID
|
||||||
|
val health = obj.Health
|
||||||
|
if (health != obj.DefaultHealth) {
|
||||||
|
sendResponse(PlanetsideAttributeMessage(guid, 0, health))
|
||||||
|
}
|
||||||
|
sendResponse(DeployableObjectsInfoMessage(DeploymentAction.Build, DeployableInfo(
|
||||||
|
guid,
|
||||||
|
Deployable.Icon(obj.Definition.Item),
|
||||||
|
obj.Position,
|
||||||
|
obj.OwnerGuid.getOrElse(Service.defaultPlayerGUID)
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* nested class - spawn operations */
|
/* nested class - spawn operations */
|
||||||
|
|
||||||
class SpawnOperations() {
|
class SpawnOperations() {
|
||||||
|
|
@ -2298,10 +2325,11 @@ class ZoningOperations(
|
||||||
//vehicle and driver/passenger
|
//vehicle and driver/passenger
|
||||||
interstellarFerry = None
|
interstellarFerry = None
|
||||||
val vdef = vehicle.Definition
|
val vdef = vehicle.Definition
|
||||||
|
val vObjectId = vdef.ObjectId
|
||||||
val vguid = vehicle.GUID
|
val vguid = vehicle.GUID
|
||||||
vehicle.Position = shiftPosition.getOrElse(vehicle.Position)
|
vehicle.Position = shiftPosition.getOrElse(vehicle.Position)
|
||||||
vehicle.Orientation = shiftOrientation.getOrElse(vehicle.Orientation)
|
vehicle.Orientation = shiftOrientation.getOrElse(vehicle.Orientation)
|
||||||
val vdata = if (seat == 0) {
|
if (seat == 0) {
|
||||||
//driver
|
//driver
|
||||||
if (vehicle.Zone ne continent) {
|
if (vehicle.Zone ne continent) {
|
||||||
continent.Transport ! Zone.Vehicle.Spawn(vehicle)
|
continent.Transport ! Zone.Vehicle.Spawn(vehicle)
|
||||||
|
|
@ -2311,7 +2339,7 @@ class ZoningOperations(
|
||||||
mount.unmount(player)
|
mount.unmount(player)
|
||||||
player.VehicleSeated = None
|
player.VehicleSeated = None
|
||||||
val data = vdef.Packet.ConstructorData(vehicle).get
|
val data = vdef.Packet.ConstructorData(vehicle).get
|
||||||
sendResponse(ObjectCreateMessage(vehicle.Definition.ObjectId, vguid, data))
|
sendResponse(ObjectCreateMessage(vObjectId, vguid, data))
|
||||||
mount.mount(player)
|
mount.mount(player)
|
||||||
player.VehicleSeated = vguid
|
player.VehicleSeated = vguid
|
||||||
Vehicles.Own(vehicle, player)
|
Vehicles.Own(vehicle, player)
|
||||||
|
|
@ -2320,7 +2348,7 @@ class ZoningOperations(
|
||||||
.foreach { _.MountedIn = vguid }
|
.foreach { _.MountedIn = vguid }
|
||||||
events ! VehicleServiceMessage(
|
events ! VehicleServiceMessage(
|
||||||
zoneid,
|
zoneid,
|
||||||
VehicleAction.LoadVehicle(player.GUID, vehicle, vdef.ObjectId, vguid, data)
|
VehicleAction.LoadVehicle(player.GUID, vehicle, vObjectId, vguid, data)
|
||||||
)
|
)
|
||||||
carrierInfo match {
|
carrierInfo match {
|
||||||
case (Some(carrier), Some((index, _))) =>
|
case (Some(carrier), Some((index, _))) =>
|
||||||
|
|
@ -2329,18 +2357,15 @@ class ZoningOperations(
|
||||||
vehicle.MountedIn = None
|
vehicle.MountedIn = None
|
||||||
}
|
}
|
||||||
vehicle.allowInteraction = true
|
vehicle.allowInteraction = true
|
||||||
data
|
|
||||||
} else {
|
} else {
|
||||||
//passenger
|
//passenger
|
||||||
//non-drivers are not rendered in the vehicle at this time
|
//non-drivers are not rendered in the vehicle at this time
|
||||||
val data = vdef.Packet.ConstructorData(vehicle).get
|
sendResponse(OCM.apply(vehicle))
|
||||||
sendResponse(ObjectCreateMessage(vehicle.Definition.ObjectId, vguid, data))
|
|
||||||
carrierInfo match {
|
carrierInfo match {
|
||||||
case (Some(carrier), Some((index, _))) =>
|
case (Some(carrier), Some((index, _))) =>
|
||||||
CargoMountBehaviorForUs(carrier, vehicle, index)
|
CargoMountBehaviorForUs(carrier, vehicle, index)
|
||||||
case _ => ()
|
case _ => ()
|
||||||
}
|
}
|
||||||
data
|
|
||||||
}
|
}
|
||||||
val originalSeated = player.VehicleSeated
|
val originalSeated = player.VehicleSeated
|
||||||
player.VehicleSeated = vguid
|
player.VehicleSeated = vguid
|
||||||
|
|
@ -2357,25 +2382,26 @@ class ZoningOperations(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Vehicles.ReloadAccessPermissions(vehicle, player.Name)
|
Vehicles.ReloadAccessPermissions(vehicle, player.Name)
|
||||||
log.debug(s"AvatarCreate (vehicle): ${player.Name}'s ${vehicle.Definition.Name}")
|
log.debug(s"AvatarCreate (vehicle): ${player.Name}'s ${vdef.Name}")
|
||||||
log.trace(s"AvatarCreate (vehicle): ${player.Name}'s ${vehicle.Definition.Name} - $vguid -> $vdata")
|
|
||||||
AvatarCreateInVehicle(player, vehicle, seat)
|
AvatarCreateInVehicle(player, vehicle, seat)
|
||||||
|
|
||||||
case _ =>
|
case _ =>
|
||||||
player.VehicleSeated = None
|
player.VehicleSeated = None
|
||||||
val packet = player.avatar.definition.Packet
|
val definition = player.avatar.definition
|
||||||
val data = packet.DetailedConstructorData(player).get
|
val guid = player.GUID
|
||||||
val guid = player.GUID
|
sendResponse(OCM.detailed(player))
|
||||||
sendResponse(ObjectCreateDetailedMessage(ObjectClass.avatar, guid, data))
|
|
||||||
continent.AvatarEvents ! AvatarServiceMessage(
|
continent.AvatarEvents ! AvatarServiceMessage(
|
||||||
zoneid,
|
zoneid,
|
||||||
AvatarAction.LoadPlayer(guid, ObjectClass.avatar, guid, packet.ConstructorData(player).get, None)
|
AvatarAction.LoadPlayer(guid, definition.ObjectId, guid, definition.Packet.ConstructorData(player).get, None)
|
||||||
)
|
)
|
||||||
log.debug(s"AvatarCreate: ${player.Name}")
|
|
||||||
log.trace(s"AvatarCreate: ${player.Name} - $guid -> $data")
|
|
||||||
}
|
}
|
||||||
continent.Population ! Zone.Population.Spawn(avatar, player, avatarActor)
|
continent.Population ! Zone.Population.Spawn(avatar, player, avatarActor)
|
||||||
avatarActor ! AvatarActor.RefreshPurchaseTimes()
|
avatarActor ! AvatarActor.RefreshPurchaseTimes()
|
||||||
|
drawDeployableIconsOnMap(
|
||||||
|
depictDeployablesUponRevival(
|
||||||
|
reclaimOurDeployables(continent.DeployableList, player.Name, reassignDeployablesTo(player.GUID))
|
||||||
|
)
|
||||||
|
)
|
||||||
//begin looking for conditions to set the avatar
|
//begin looking for conditions to set the avatar
|
||||||
context.system.scheduler.scheduleOnce(delay = 250 millisecond, context.self, SessionActor.SetCurrentAvatar(player, 200))
|
context.system.scheduler.scheduleOnce(delay = 250 millisecond, context.self, SessionActor.SetCurrentAvatar(player, 200))
|
||||||
}
|
}
|
||||||
|
|
@ -2403,11 +2429,9 @@ class ZoningOperations(
|
||||||
val pguid = tplayer.GUID
|
val pguid = tplayer.GUID
|
||||||
val vguid = vehicle.GUID
|
val vguid = vehicle.GUID
|
||||||
tplayer.VehicleSeated = None
|
tplayer.VehicleSeated = None
|
||||||
val pdata = pdef.Packet.DetailedConstructorData(tplayer).get
|
|
||||||
tplayer.VehicleSeated = vguid
|
tplayer.VehicleSeated = vguid
|
||||||
log.debug(s"AvatarCreateInVehicle: ${player.Name}")
|
log.debug(s"AvatarCreateInVehicle: ${player.Name}")
|
||||||
log.trace(s"AvatarCreateInVehicle: ${player.Name} - $pguid -> $pdata")
|
sendResponse(OCM.detailed(tplayer))
|
||||||
sendResponse(ObjectCreateDetailedMessage(pdef.ObjectId, pguid, pdata))
|
|
||||||
if (seat == 0 || vehicle.WeaponControlledFromSeat(seat).nonEmpty) {
|
if (seat == 0 || vehicle.WeaponControlledFromSeat(seat).nonEmpty) {
|
||||||
sendResponse(ObjectAttachMessage(vguid, pguid, seat))
|
sendResponse(ObjectAttachMessage(vguid, pguid, seat))
|
||||||
sessionLogic.general.accessContainer(vehicle)
|
sessionLogic.general.accessContainer(vehicle)
|
||||||
|
|
@ -2459,13 +2483,10 @@ class ZoningOperations(
|
||||||
sessionLogic.vehicles.GetKnownVehicleAndSeat() match {
|
sessionLogic.vehicles.GetKnownVehicleAndSeat() match {
|
||||||
case (Some(vehicle: Vehicle), Some(seat: Int)) =>
|
case (Some(vehicle: Vehicle), Some(seat: Int)) =>
|
||||||
//vehicle and driver/passenger
|
//vehicle and driver/passenger
|
||||||
val vdef = vehicle.Definition
|
|
||||||
val vguid = vehicle.GUID
|
val vguid = vehicle.GUID
|
||||||
val vdata = vdef.Packet.ConstructorData(vehicle).get
|
sendResponse(OCM.apply(vehicle))
|
||||||
sendResponse(ObjectCreateMessage(vehicle.Definition.ObjectId, vguid, vdata))
|
|
||||||
Vehicles.ReloadAccessPermissions(vehicle, continent.id)
|
Vehicles.ReloadAccessPermissions(vehicle, continent.id)
|
||||||
log.debug(s"AvatarCreate (vehicle): ${player.Name}'s ${vehicle.Definition.Name}")
|
log.debug(s"AvatarCreate (vehicle): ${player.Name}'s ${vehicle.Definition.Name}")
|
||||||
log.trace(s"AvatarCreate (vehicle): ${player.Name}'s ${vehicle.Definition.Name} - $vguid -> $vdata")
|
|
||||||
val pdef = player.avatar.definition
|
val pdef = player.avatar.definition
|
||||||
val pguid = player.GUID
|
val pguid = player.GUID
|
||||||
player.VehicleSeated = None
|
player.VehicleSeated = None
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ import net.psforever.objects.vital.interaction.DamageInteraction
|
||||||
import net.psforever.objects.zones.Zone
|
import net.psforever.objects.zones.Zone
|
||||||
import net.psforever.services.Service
|
import net.psforever.services.Service
|
||||||
import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
|
import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
|
||||||
|
import net.psforever.services.local.{LocalAction, LocalServiceMessage}
|
||||||
import net.psforever.types.PlanetSideEmpire
|
import net.psforever.types.PlanetSideEmpire
|
||||||
|
|
||||||
import scala.annotation.unused
|
import scala.annotation.unused
|
||||||
|
|
@ -81,8 +82,14 @@ class BoomerDeployableControl(mine: BoomerDeployable)
|
||||||
}
|
}
|
||||||
|
|
||||||
override def gainOwnership(player: Player): Unit = {
|
override def gainOwnership(player: Player): Unit = {
|
||||||
mine.Faction = PlanetSideEmpire.NEUTRAL //force map icon redraw
|
val originalOwner = mine.OwnerName
|
||||||
super.gainOwnership(player, player.Faction)
|
super.gainOwnership(player, player.Faction)
|
||||||
|
val events = mine.Zone.LocalEvents
|
||||||
|
val msg = LocalAction.DeployItem(mine)
|
||||||
|
originalOwner.collect { name =>
|
||||||
|
events ! LocalServiceMessage(name, msg)
|
||||||
|
}
|
||||||
|
events ! LocalServiceMessage(player.Name, msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
override def dismissDeployable() : Unit = {
|
override def dismissDeployable() : Unit = {
|
||||||
|
|
|
||||||
|
|
@ -18,16 +18,11 @@ trait OwnableByPlayer {
|
||||||
def OwnerGuid_=(owner: Player): Option[PlanetSideGUID] = OwnerGuid_=(Some(owner.GUID))
|
def OwnerGuid_=(owner: Player): Option[PlanetSideGUID] = OwnerGuid_=(Some(owner.GUID))
|
||||||
|
|
||||||
def OwnerGuid_=(owner: Option[PlanetSideGUID]): Option[PlanetSideGUID] = {
|
def OwnerGuid_=(owner: Option[PlanetSideGUID]): Option[PlanetSideGUID] = {
|
||||||
owner match {
|
ownerGuid = owner
|
||||||
case Some(_) =>
|
|
||||||
ownerGuid = owner
|
|
||||||
case None =>
|
|
||||||
ownerGuid = None
|
|
||||||
}
|
|
||||||
OwnerGuid
|
OwnerGuid
|
||||||
}
|
}
|
||||||
|
|
||||||
def OwnerName: Option[String] = owner.map { _.name }
|
def OwnerName: Option[String] = owner.map(_.name)
|
||||||
|
|
||||||
def OriginalOwnerName: Option[String] = originalOwnerName
|
def OriginalOwnerName: Option[String] = originalOwnerName
|
||||||
|
|
||||||
|
|
@ -47,7 +42,7 @@ trait OwnableByPlayer {
|
||||||
(originalOwnerName, playerOpt) match {
|
(originalOwnerName, playerOpt) match {
|
||||||
case (None, Some(player)) =>
|
case (None, Some(player)) =>
|
||||||
owner = Some(UniquePlayer(player))
|
owner = Some(UniquePlayer(player))
|
||||||
originalOwnerName = originalOwnerName.orElse { Some(player.Name) }
|
originalOwnerName = originalOwnerName.orElse(Some(player.Name))
|
||||||
OwnerGuid = player
|
OwnerGuid = player
|
||||||
case (_, Some(player)) =>
|
case (_, Some(player)) =>
|
||||||
owner = Some(UniquePlayer(player))
|
owner = Some(UniquePlayer(player))
|
||||||
|
|
|
||||||
|
|
@ -524,7 +524,7 @@ class PlayerControl(player: Player, avatarActor: typed.ActorRef[AvatarActor.Comm
|
||||||
log.warn(s"${player.Name} failed to pick up an item ($item_guid) from the ground because $reason")
|
log.warn(s"${player.Name} failed to pick up an item ($item_guid) from the ground because $reason")
|
||||||
|
|
||||||
case Player.BuildDeployable(obj: TelepadDeployable, tool: Telepad) =>
|
case Player.BuildDeployable(obj: TelepadDeployable, tool: Telepad) =>
|
||||||
obj.Router = tool.Router //necessary; forwards link to the router that prodcued the telepad
|
obj.Router = tool.Router //necessary; forwards link to the router that produced the telepad
|
||||||
setupDeployable(obj, tool)
|
setupDeployable(obj, tool)
|
||||||
|
|
||||||
case Player.BuildDeployable(obj, tool) =>
|
case Player.BuildDeployable(obj, tool) =>
|
||||||
|
|
@ -534,7 +534,6 @@ class PlayerControl(player: Player, avatarActor: typed.ActorRef[AvatarActor.Comm
|
||||||
deployablePair match {
|
deployablePair match {
|
||||||
case Some((deployable, tool)) if deployable eq obj =>
|
case Some((deployable, tool)) if deployable eq obj =>
|
||||||
val zone = player.Zone
|
val zone = player.Zone
|
||||||
//boomers
|
|
||||||
val trigger = new BoomerTrigger
|
val trigger = new BoomerTrigger
|
||||||
trigger.Companion = obj.GUID
|
trigger.Companion = obj.GUID
|
||||||
obj.Trigger = trigger
|
obj.Trigger = trigger
|
||||||
|
|
@ -552,7 +551,7 @@ class PlayerControl(player: Player, avatarActor: typed.ActorRef[AvatarActor.Comm
|
||||||
TaskWorkflow.execute(PutNewEquipmentInInventoryOrDrop(player)(trigger))
|
TaskWorkflow.execute(PutNewEquipmentInInventoryOrDrop(player)(trigger))
|
||||||
}
|
}
|
||||||
Players.buildCooldownReset(zone, player.Name, obj)
|
Players.buildCooldownReset(zone, player.Name, obj)
|
||||||
case _ => ;
|
case _ => ()
|
||||||
}
|
}
|
||||||
deployablePair = None
|
deployablePair = None
|
||||||
|
|
||||||
|
|
@ -569,7 +568,7 @@ class PlayerControl(player: Player, avatarActor: typed.ActorRef[AvatarActor.Comm
|
||||||
TelepadControl.TelepadError(zone, player.Name, msg = "@Telepad_NoDeploy_RouterLost")
|
TelepadControl.TelepadError(zone, player.Name, msg = "@Telepad_NoDeploy_RouterLost")
|
||||||
}
|
}
|
||||||
Players.buildCooldownReset(zone, player.Name, obj)
|
Players.buildCooldownReset(zone, player.Name, obj)
|
||||||
case _ => ;
|
case _ => ()
|
||||||
}
|
}
|
||||||
deployablePair = None
|
deployablePair = None
|
||||||
|
|
||||||
|
|
@ -584,7 +583,7 @@ class PlayerControl(player: Player, avatarActor: typed.ActorRef[AvatarActor.Comm
|
||||||
case None =>
|
case None =>
|
||||||
log.warn(s"${player.Name} should have destroyed a ${tool.Definition.Name} here, but could not find it")
|
log.warn(s"${player.Name} should have destroyed a ${tool.Definition.Name} here, but could not find it")
|
||||||
}
|
}
|
||||||
case _ => ;
|
case _ => ()
|
||||||
}
|
}
|
||||||
deployablePair = None
|
deployablePair = None
|
||||||
|
|
||||||
|
|
@ -701,16 +700,27 @@ class PlayerControl(player: Player, avatarActor: typed.ActorRef[AvatarActor.Comm
|
||||||
if (deployables.Valid(obj) &&
|
if (deployables.Valid(obj) &&
|
||||||
!deployables.Contains(obj) &&
|
!deployables.Contains(obj) &&
|
||||||
Players.deployableWithinBuildLimits(player, obj)) {
|
Players.deployableWithinBuildLimits(player, obj)) {
|
||||||
|
//deployables, upon construction, may display an animation effect
|
||||||
tool.Definition match {
|
tool.Definition match {
|
||||||
case GlobalDefinitions.ace | /* animation handled in deployable lifecycle */
|
case GlobalDefinitions.router_telepad => () /* no special animation */
|
||||||
GlobalDefinitions.router_telepad => ; /* no special animation */
|
case GlobalDefinitions.ace
|
||||||
|
if obj.Definition.deployAnimation == DeployAnimation.Standard =>
|
||||||
|
zone.LocalEvents ! LocalServiceMessage(
|
||||||
|
zone.id,
|
||||||
|
LocalAction.TriggerEffectLocation(
|
||||||
|
obj.OwnerGuid.getOrElse(Service.defaultPlayerGUID),
|
||||||
|
"spawn_object_effect",
|
||||||
|
obj.Position,
|
||||||
|
obj.Orientation
|
||||||
|
)
|
||||||
|
)
|
||||||
case GlobalDefinitions.advanced_ace
|
case GlobalDefinitions.advanced_ace
|
||||||
if obj.Definition.deployAnimation == DeployAnimation.Fdu =>
|
if obj.Definition.deployAnimation == DeployAnimation.Fdu =>
|
||||||
zone.AvatarEvents ! AvatarServiceMessage(zone.id, AvatarAction.PutDownFDU(player.GUID))
|
zone.AvatarEvents ! AvatarServiceMessage(zone.id, AvatarAction.PutDownFDU(player.GUID))
|
||||||
case _ =>
|
case _ =>
|
||||||
org.log4s.getLogger(name = "Deployables").warn(
|
org.log4s
|
||||||
s"not sure what kind of construction item to animate - ${tool.Definition.Name}"
|
.getLogger(name = "Deployables")
|
||||||
)
|
.warn(s"not sure what kind of construction item to animate - ${tool.Definition.Name}")
|
||||||
}
|
}
|
||||||
deployablePair = Some((obj, tool))
|
deployablePair = Some((obj, tool))
|
||||||
obj.Faction = player.Faction
|
obj.Faction = player.Faction
|
||||||
|
|
@ -1158,10 +1168,14 @@ class PlayerControl(player: Player, avatarActor: typed.ActorRef[AvatarActor.Comm
|
||||||
zone.GUID(trigger.Companion) match {
|
zone.GUID(trigger.Companion) match {
|
||||||
case Some(obj: BoomerDeployable) =>
|
case Some(obj: BoomerDeployable) =>
|
||||||
val deployables = player.avatar.deployables
|
val deployables = player.avatar.deployables
|
||||||
if (deployables.Valid(obj)) {
|
if (!deployables.Contains(obj) && deployables.Valid(obj)) {
|
||||||
|
events ! AvatarServiceMessage(toChannel, AvatarAction.SendResponse(
|
||||||
|
Service.defaultPlayerGUID,
|
||||||
|
GenericObjectAction2Message(1, player.GUID, trigger.GUID)
|
||||||
|
))
|
||||||
Players.gainDeployableOwnership(player, obj, deployables.AddOverLimit)
|
Players.gainDeployableOwnership(player, obj, deployables.AddOverLimit)
|
||||||
}
|
}
|
||||||
case _ => ;
|
case _ => ()
|
||||||
}
|
}
|
||||||
|
|
||||||
case citem: ConstructionItem
|
case citem: ConstructionItem
|
||||||
|
|
@ -1172,7 +1186,7 @@ class PlayerControl(player: Player, avatarActor: typed.ActorRef[AvatarActor.Comm
|
||||||
}
|
}
|
||||||
Deployables.initializeConstructionItem(player.avatar.certifications, citem)
|
Deployables.initializeConstructionItem(player.avatar.certifications, citem)
|
||||||
|
|
||||||
case _ => ;
|
case _ => ()
|
||||||
}
|
}
|
||||||
events ! AvatarServiceMessage(
|
events ! AvatarServiceMessage(
|
||||||
toChannel,
|
toChannel,
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,6 @@ package net.psforever.objects.ce
|
||||||
import akka.actor.{Actor, ActorRef, Cancellable}
|
import akka.actor.{Actor, ActorRef, Cancellable}
|
||||||
import net.psforever.objects.guid.{GUIDTask, TaskWorkflow}
|
import net.psforever.objects.guid.{GUIDTask, TaskWorkflow}
|
||||||
import net.psforever.objects._
|
import net.psforever.objects._
|
||||||
import net.psforever.objects.definition.DeployAnimation
|
|
||||||
import net.psforever.objects.zones.Zone
|
import net.psforever.objects.zones.Zone
|
||||||
import net.psforever.packet.game._
|
import net.psforever.packet.game._
|
||||||
import net.psforever.services.Service
|
import net.psforever.services.Service
|
||||||
|
|
@ -75,7 +74,7 @@ trait DeployableBehavior {
|
||||||
}
|
}
|
||||||
|
|
||||||
case Deployable.Ownership(Some(player))
|
case Deployable.Ownership(Some(player))
|
||||||
if !DeployableObject.Destroyed && DeployableObject.OwnerGuid.isEmpty =>
|
if !DeployableObject.Destroyed /*&& DeployableObject.OwnerGuid.isEmpty*/ =>
|
||||||
if (constructed.contains(true)) {
|
if (constructed.contains(true)) {
|
||||||
gainOwnership(player)
|
gainOwnership(player)
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -105,6 +104,7 @@ trait DeployableBehavior {
|
||||||
def loseOwnership(obj: Deployable, toFaction: PlanetSideEmpire.Value): Unit = {
|
def loseOwnership(obj: Deployable, toFaction: PlanetSideEmpire.Value): Unit = {
|
||||||
DeployableBehavior.changeOwnership(
|
DeployableBehavior.changeOwnership(
|
||||||
obj,
|
obj,
|
||||||
|
toOwner = "",
|
||||||
toFaction,
|
toFaction,
|
||||||
DeployableInfo(obj.GUID, Deployable.Icon.apply(obj.Definition.Item), obj.Position, Service.defaultPlayerGUID)
|
DeployableInfo(obj.GUID, Deployable.Icon.apply(obj.Definition.Item), obj.Position, Service.defaultPlayerGUID)
|
||||||
)
|
)
|
||||||
|
|
@ -138,18 +138,18 @@ trait DeployableBehavior {
|
||||||
*/
|
*/
|
||||||
def gainOwnership(player: Player, toFaction: PlanetSideEmpire.Value): Unit = {
|
def gainOwnership(player: Player, toFaction: PlanetSideEmpire.Value): Unit = {
|
||||||
val obj = DeployableObject
|
val obj = DeployableObject
|
||||||
obj.AssignOwnership(player)
|
|
||||||
decay.cancel()
|
decay.cancel()
|
||||||
DeployableBehavior.changeOwnership(
|
DeployableBehavior.changeOwnership(
|
||||||
obj,
|
obj,
|
||||||
|
player.Name,
|
||||||
toFaction,
|
toFaction,
|
||||||
DeployableInfo(obj.GUID, Deployable.Icon.apply(obj.Definition.Item), obj.Position, obj.OwnerGuid.get)
|
DeployableInfo(obj.GUID, Deployable.Icon.apply(obj.Definition.Item), obj.Position, player.GUID)
|
||||||
)
|
)
|
||||||
|
obj.AssignOwnership(player)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The first stage of the deployable build process, to put the formal process in motion.
|
* The first stage of the deployable build process, to put the formal process in motion.
|
||||||
* Deployables, upon construction, may display an animation effect.
|
|
||||||
* Parameters are required to be passed onto the next stage of the build process and are not used here.
|
* Parameters are required to be passed onto the next stage of the build process and are not used here.
|
||||||
* @see `DeployableDefinition.deployAnimation`
|
* @see `DeployableDefinition.deployAnimation`
|
||||||
* @see `DeployableDefinition.DeployTime`
|
* @see `DeployableDefinition.DeployTime`
|
||||||
|
|
@ -157,21 +157,9 @@ trait DeployableBehavior {
|
||||||
* @param callback an `ActorRef` used for confirming the deployable's completion of the process
|
* @param callback an `ActorRef` used for confirming the deployable's completion of the process
|
||||||
*/
|
*/
|
||||||
def setupDeployable(callback: ActorRef): Unit = {
|
def setupDeployable(callback: ActorRef): Unit = {
|
||||||
|
import scala.concurrent.ExecutionContext.Implicits.global
|
||||||
val obj = DeployableObject
|
val obj = DeployableObject
|
||||||
constructed = Some(false)
|
constructed = Some(false)
|
||||||
if (obj.Definition.deployAnimation == DeployAnimation.Standard) {
|
|
||||||
val zone = obj.Zone
|
|
||||||
zone.LocalEvents ! LocalServiceMessage(
|
|
||||||
zone.id,
|
|
||||||
LocalAction.TriggerEffectLocation(
|
|
||||||
obj.OwnerGuid.getOrElse(Service.defaultPlayerGUID),
|
|
||||||
"spawn_object_effect",
|
|
||||||
obj.Position,
|
|
||||||
obj.Orientation
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
import scala.concurrent.ExecutionContext.Implicits.global
|
|
||||||
setup = context.system.scheduler.scheduleOnce(
|
setup = context.system.scheduler.scheduleOnce(
|
||||||
obj.Definition.DeployTime milliseconds,
|
obj.Definition.DeployTime milliseconds,
|
||||||
self,
|
self,
|
||||||
|
|
@ -185,7 +173,7 @@ trait DeployableBehavior {
|
||||||
* Nothing dangerous happens if it does not begin to decay, but, because it is not under a player's management,
|
* Nothing dangerous happens if it does not begin to decay, but, because it is not under a player's management,
|
||||||
* the deployable will not properly transition to a decay state for another reason
|
* the deployable will not properly transition to a decay state for another reason
|
||||||
* and can linger in the zone ownerless for as long as it is not destroyed.
|
* and can linger in the zone ownerless for as long as it is not destroyed.
|
||||||
* @see `AvatarAction.DeployItem`
|
* @see `LocalAction.DeployItem`
|
||||||
* @see `DeploymentAction`
|
* @see `DeploymentAction`
|
||||||
* @see `DeployableInfo`
|
* @see `DeployableInfo`
|
||||||
* @see `LocalAction.DeployableMapIcon`
|
* @see `LocalAction.DeployableMapIcon`
|
||||||
|
|
@ -197,27 +185,22 @@ trait DeployableBehavior {
|
||||||
setup = Default.Cancellable
|
setup = Default.Cancellable
|
||||||
constructed = Some(true)
|
constructed = Some(true)
|
||||||
val obj = DeployableObject
|
val obj = DeployableObject
|
||||||
val zone = obj.Zone
|
val zone = obj.Zone
|
||||||
val localEvents = zone.LocalEvents
|
val localEvents = zone.LocalEvents
|
||||||
val owner = obj.OwnerGuid.getOrElse(Service.defaultPlayerGUID)
|
obj.OwnerName.orElse {
|
||||||
obj.OwnerName match {
|
import scala.concurrent.ExecutionContext.Implicits.global
|
||||||
case Some(_) =>
|
decay = context.system.scheduler.scheduleOnce(Deployable.decay, self, Deployable.Deconstruct())
|
||||||
case None =>
|
None
|
||||||
import scala.concurrent.ExecutionContext.Implicits.global
|
|
||||||
decay = context.system.scheduler.scheduleOnce(
|
|
||||||
Deployable.decay,
|
|
||||||
self,
|
|
||||||
Deployable.Deconstruct()
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
//zone build
|
//zone build
|
||||||
zone.AvatarEvents ! AvatarServiceMessage(zone.id, AvatarAction.DeployItem(Service.defaultPlayerGUID, obj))
|
localEvents ! LocalServiceMessage(zone.id, LocalAction.DeployItem(obj))
|
||||||
//zone map icon
|
//zone map icon
|
||||||
localEvents ! LocalServiceMessage(
|
localEvents ! LocalServiceMessage(
|
||||||
obj.Faction.toString,
|
obj.Faction.toString,
|
||||||
LocalAction.DeployableMapIcon(
|
LocalAction.DeployableMapIcon(
|
||||||
Service.defaultPlayerGUID,
|
Service.defaultPlayerGUID,
|
||||||
DeploymentAction.Build, DeployableInfo(obj.GUID, Deployable.Icon(obj.Definition.Item), obj.Position, owner)
|
DeploymentAction.Build,
|
||||||
|
DeployableInfo(obj.GUID, Deployable.Icon(obj.Definition.Item), obj.Position, obj.OwnerGuid.getOrElse(Service.defaultPlayerGUID))
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
//local build management
|
//local build management
|
||||||
|
|
@ -290,28 +273,28 @@ object DeployableBehavior {
|
||||||
* @param toFaction na
|
* @param toFaction na
|
||||||
* @param info na
|
* @param info na
|
||||||
*/
|
*/
|
||||||
def changeOwnership(obj: Deployable, toFaction: PlanetSideEmpire.Value, info: DeployableInfo): Unit = {
|
def changeOwnership(obj: Deployable, toOwner: String, toFaction: PlanetSideEmpire.Value, info: DeployableInfo): Unit = {
|
||||||
|
val dGuid = obj.GUID
|
||||||
val originalFaction = obj.Faction
|
val originalFaction = obj.Faction
|
||||||
|
val zone = obj.Zone
|
||||||
|
val localEvents = zone.LocalEvents
|
||||||
if (originalFaction != toFaction) {
|
if (originalFaction != toFaction) {
|
||||||
val guid = obj.GUID
|
|
||||||
val zone = obj.Zone
|
|
||||||
val localEvents = zone.LocalEvents
|
|
||||||
obj.Faction = toFaction
|
obj.Faction = toFaction
|
||||||
//visual tells in regards to ownership by faction
|
//visual tells in regards to ownership by faction
|
||||||
zone.AvatarEvents ! AvatarServiceMessage(
|
zone.AvatarEvents ! AvatarServiceMessage(
|
||||||
zone.id,
|
zone.id,
|
||||||
AvatarAction.SetEmpire(Service.defaultPlayerGUID, guid, toFaction)
|
AvatarAction.SetEmpire(Service.defaultPlayerGUID, dGuid, toFaction)
|
||||||
)
|
)
|
||||||
//remove knowledge by the previous owner's faction
|
//remove knowledge by the previous owner's faction
|
||||||
localEvents ! LocalServiceMessage(
|
localEvents ! LocalServiceMessage(
|
||||||
originalFaction.toString,
|
originalFaction.toString,
|
||||||
LocalAction.DeployableMapIcon(Service.defaultPlayerGUID, DeploymentAction.Dismiss, info)
|
LocalAction.DeployableMapIcon(Service.defaultPlayerGUID, DeploymentAction.Dismiss, info)
|
||||||
)
|
)
|
||||||
//display to the given faction
|
|
||||||
localEvents ! LocalServiceMessage(
|
|
||||||
toFaction.toString,
|
|
||||||
LocalAction.DeployableMapIcon(Service.defaultPlayerGUID, DeploymentAction.Build, info)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
//display to the given faction
|
||||||
|
localEvents ! LocalServiceMessage(
|
||||||
|
toFaction.toString,
|
||||||
|
LocalAction.DeployableMapIcon(Service.defaultPlayerGUID, DeploymentAction.Build, info)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ class SmallTurretConverter extends ObjectCreateConverter[TurretDeployable]() {
|
||||||
v1 = true,
|
v1 = true,
|
||||||
None,
|
None,
|
||||||
obj.Jammed,
|
obj.Jammed,
|
||||||
Some(true),
|
None,
|
||||||
None,
|
None,
|
||||||
obj.OwnerGuid match {
|
obj.OwnerGuid match {
|
||||||
case Some(owner) => owner
|
case Some(owner) => owner
|
||||||
|
|
@ -67,7 +67,7 @@ object SmallTurretConverter {
|
||||||
private def MakeMountings(obj: WeaponTurret): List[InventoryItemData.InventoryItem] = {
|
private def MakeMountings(obj: WeaponTurret): List[InventoryItemData.InventoryItem] = {
|
||||||
obj.Weapons
|
obj.Weapons
|
||||||
.map({
|
.map({
|
||||||
case ((index, slot)) =>
|
case (index, slot) =>
|
||||||
val equip: Equipment = slot.Equipment.get
|
val equip: Equipment = slot.Equipment.get
|
||||||
val equipDef = equip.Definition
|
val equipDef = equip.Definition
|
||||||
InventoryItemData(equipDef.ObjectId, equip.GUID, index, equipDef.Packet.ConstructorData(equip).get)
|
InventoryItemData(equipDef.ObjectId, equip.GUID, index, equipDef.Packet.ConstructorData(equip).get)
|
||||||
|
|
|
||||||
|
|
@ -19,10 +19,10 @@ class TRAPConverter extends ObjectCreateConverter[TrapDeployable]() {
|
||||||
obj.Faction,
|
obj.Faction,
|
||||||
bops = false,
|
bops = false,
|
||||||
alternate = false,
|
alternate = false,
|
||||||
true,
|
v1 = true,
|
||||||
|
None,
|
||||||
|
jammered = false,
|
||||||
None,
|
None,
|
||||||
false,
|
|
||||||
Some(true),
|
|
||||||
None,
|
None,
|
||||||
obj.OwnerGuid match {
|
obj.OwnerGuid match {
|
||||||
case Some(owner) => owner
|
case Some(owner) => owner
|
||||||
|
|
@ -42,9 +42,9 @@ class TRAPConverter extends ObjectCreateConverter[TrapDeployable]() {
|
||||||
obj.Faction,
|
obj.Faction,
|
||||||
bops = false,
|
bops = false,
|
||||||
alternate = true,
|
alternate = true,
|
||||||
true,
|
v1 = true,
|
||||||
None,
|
None,
|
||||||
false,
|
jammered = false,
|
||||||
Some(true),
|
Some(true),
|
||||||
None,
|
None,
|
||||||
PlanetSideGUID(0)
|
PlanetSideGUID(0)
|
||||||
|
|
|
||||||
|
|
@ -455,7 +455,7 @@ object GamePacketOpcode extends Enumeration {
|
||||||
case 0x7f => game.AvatarStatisticsMessage.decode
|
case 0x7f => game.AvatarStatisticsMessage.decode
|
||||||
|
|
||||||
// OPCODES 0x80-8f
|
// OPCODES 0x80-8f
|
||||||
case 0x80 => noDecoder(GenericObjectAction2Message)
|
case 0x80 => game.GenericObjectAction2Message.decode
|
||||||
case 0x81 => game.DestroyDisplayMessage.decode
|
case 0x81 => game.DestroyDisplayMessage.decode
|
||||||
case 0x82 => noDecoder(TriggerBotAction)
|
case 0x82 => noDecoder(TriggerBotAction)
|
||||||
case 0x83 => game.SquadWaypointRequest.decode
|
case 0x83 => game.SquadWaypointRequest.decode
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
// Copyright (c) 2024 PSForever
|
||||||
|
package net.psforever.packet.game
|
||||||
|
|
||||||
|
import net.psforever.packet.GamePacketOpcode.Type
|
||||||
|
import net.psforever.packet.{GamePacketOpcode, Marshallable, PlanetSideGamePacket}
|
||||||
|
import net.psforever.types.PlanetSideGUID
|
||||||
|
import scodec.bits.BitVector
|
||||||
|
import scodec.codecs._
|
||||||
|
import scodec.{Attempt, Codec}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* na
|
||||||
|
* @param unk na
|
||||||
|
* @param guid1 na
|
||||||
|
* @param guid2 na
|
||||||
|
*/
|
||||||
|
final case class GenericObjectAction2Message(
|
||||||
|
unk: Int,
|
||||||
|
guid1: PlanetSideGUID,
|
||||||
|
guid2: PlanetSideGUID
|
||||||
|
) extends PlanetSideGamePacket {
|
||||||
|
type Packet = GenericObjectActionMessage
|
||||||
|
def opcode: Type = GamePacketOpcode.GenericObjectAction2Message
|
||||||
|
def encode: Attempt[BitVector] = GenericObjectAction2Message.encode(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
object GenericObjectAction2Message extends Marshallable[GenericObjectAction2Message] {
|
||||||
|
implicit val codec: Codec[GenericObjectAction2Message] = (
|
||||||
|
("unk" | uint(bits = 3)) :: //dword_D32FC0
|
||||||
|
("guid1" | PlanetSideGUID.codec) ::
|
||||||
|
("guid2" | PlanetSideGUID.codec)
|
||||||
|
).as[GenericObjectAction2Message]
|
||||||
|
}
|
||||||
|
|
@ -1,10 +1,12 @@
|
||||||
// Copyright (c) 2016 PSForever.net to present
|
// Copyright (c) 2016 PSForever.net to present
|
||||||
package net.psforever.packet.game
|
package net.psforever.packet.game
|
||||||
|
|
||||||
|
import net.psforever.packet.GamePacketOpcode.Type
|
||||||
import net.psforever.packet.game.PlanetsideAttributeEnum.PlanetsideAttributeEnum
|
import net.psforever.packet.game.PlanetsideAttributeEnum.PlanetsideAttributeEnum
|
||||||
import net.psforever.packet.{GamePacketOpcode, Marshallable, PlanetSideGamePacket}
|
import net.psforever.packet.{GamePacketOpcode, Marshallable, 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._
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -68,8 +70,8 @@ import scodec.codecs._
|
||||||
* `17 - BEP. Value seems to be the same as BattleExperienceMessage`<br>
|
* `17 - BEP. Value seems to be the same as BattleExperienceMessage`<br>
|
||||||
* `18 - CEP.`<br>
|
* `18 - CEP.`<br>
|
||||||
* `19 - Anchors. Value is 0 to disengage, 1 to engage.`<br>
|
* `19 - Anchors. Value is 0 to disengage, 1 to engage.`<br>
|
||||||
* `20 - Control console hacking, affects CC timer, yellow base warning lights and message "The FactionName has hacked into BaseName".
|
* `20 - Control console hacking, affects CC timer, yellow base warning lights and message "The FactionName has hacked into BaseName".`
|
||||||
* Format is: Time left - 2 bytes, faction - 1 byte (1-4), isResecured - 1 byte (0-1)`<br>
|
* Format is: Time left - 2 bytes, faction - 1 byte (1-4), isResecured - 1 byte (0-1)<br>
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li>65535 segments per faction in deciseconds (seconds * 10)</li>
|
* <li>65535 segments per faction in deciseconds (seconds * 10)</li>
|
||||||
* <li>0-65535 = Neutral 0 seconds to 1h 49m 14s - 0x0000 to 0xFFFF</li>
|
* <li>0-65535 = Neutral 0 seconds to 1h 49m 14s - 0x0000 to 0xFFFF</li>
|
||||||
|
|
@ -134,8 +136,8 @@ import scodec.codecs._
|
||||||
* `31 - Looking for Squad info (marquee and ui):`<br>
|
* `31 - Looking for Squad info (marquee and ui):`<br>
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li>0 - LFS</li>
|
* <li>0 - LFS</li>
|
||||||
* <li>1 is LFSM (Looking for Squad Members)`</li>
|
* <li>1 is LFSM (Looking for Squad Members)</li>
|
||||||
* <li>`n` is the supplemental squad identifier number; same as "LFS;" for the leader, sets "LFSM" after the first manual flagging`</li>
|
* <li>`n` is the supplemental squad identifier number; same as "LFS;" for the leader, sets "LFSM" after the first manual flagging</li>
|
||||||
* </ul>
|
* </ul>
|
||||||
* `32 - Maintain the squad role index, when a member of a squad`<br>
|
* `32 - Maintain the squad role index, when a member of a squad`<br>
|
||||||
* `35 - Battle Rank`<br>
|
* `35 - Battle Rank`<br>
|
||||||
|
|
@ -204,8 +206,8 @@ import scodec.codecs._
|
||||||
final case class PlanetsideAttributeMessage(guid: PlanetSideGUID, attribute_type: Int, attribute_value: Long)
|
final case class PlanetsideAttributeMessage(guid: PlanetSideGUID, attribute_type: Int, attribute_value: Long)
|
||||||
extends PlanetSideGamePacket {
|
extends PlanetSideGamePacket {
|
||||||
type Packet = PlanetsideAttributeMessage
|
type Packet = PlanetsideAttributeMessage
|
||||||
def opcode = GamePacketOpcode.PlanetsideAttributeMessage
|
def opcode: Type = GamePacketOpcode.PlanetsideAttributeMessage
|
||||||
def encode = PlanetsideAttributeMessage.encode(this)
|
def encode: Attempt[BitVector] = PlanetsideAttributeMessage.encode(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
object PlanetsideAttributeMessage extends Marshallable[PlanetsideAttributeMessage] {
|
object PlanetsideAttributeMessage extends Marshallable[PlanetsideAttributeMessage] {
|
||||||
|
|
@ -235,5 +237,6 @@ object PlanetsideAttributeMessage extends Marshallable[PlanetsideAttributeMessag
|
||||||
object PlanetsideAttributeEnum extends Enumeration {
|
object PlanetsideAttributeEnum extends Enumeration {
|
||||||
type PlanetsideAttributeEnum = Value
|
type PlanetsideAttributeEnum = Value
|
||||||
|
|
||||||
val ControlConsoleHackUpdate = Value(20)
|
val ControlConsoleHackUpdate: PlanetsideAttributeEnum.Value = Value(20)
|
||||||
|
val OwnershipAssignment: PlanetsideAttributeEnum.Value = Value(21)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,10 @@ object AegisShieldGeneratorData extends Marshallable[AegisShieldGeneratorData] {
|
||||||
implicit val codec: Codec[AegisShieldGeneratorData] = (
|
implicit val codec: Codec[AegisShieldGeneratorData] = (
|
||||||
("deploy" | CommonFieldDataWithPlacement.codec) ::
|
("deploy" | CommonFieldDataWithPlacement.codec) ::
|
||||||
("health" | uint8L) ::
|
("health" | uint8L) ::
|
||||||
uint32 :: uint32 :: uint32 :: uint4L //100 bits
|
uint32 ::
|
||||||
|
uint32 ::
|
||||||
|
uint32 ::
|
||||||
|
uint4L
|
||||||
).exmap[AegisShieldGeneratorData](
|
).exmap[AegisShieldGeneratorData](
|
||||||
{
|
{
|
||||||
case deploy :: health :: 0 :: 0 :: 0 :: 0 :: HNil =>
|
case deploy :: health :: 0 :: 0 :: 0 :: 0 :: HNil =>
|
||||||
|
|
|
||||||
|
|
@ -72,7 +72,7 @@ object BattleFrameRoboticsData extends Marshallable[BattleFrameRoboticsData] {
|
||||||
("proper_anim" | bool) :: //when unflagged, bfr stands, even if unmanned
|
("proper_anim" | bool) :: //when unflagged, bfr stands, even if unmanned
|
||||||
("unk3" | uint4) ::
|
("unk3" | uint4) ::
|
||||||
("show_bfr_shield" | bool) ::
|
("show_bfr_shield" | bool) ::
|
||||||
optional(bool, target = "inventory" | MountableInventory.custom_inventory_codec(pos.vel.isDefined, VehicleFormat.Battleframe))
|
("inventory" | optional(bool, MountableInventory.custom_inventory_codec(pos.vel.isDefined, VehicleFormat.Battleframe)))
|
||||||
}
|
}
|
||||||
).exmap[BattleFrameRoboticsData] (
|
).exmap[BattleFrameRoboticsData] (
|
||||||
{
|
{
|
||||||
|
|
@ -107,7 +107,7 @@ object BattleFrameRoboticsData extends Marshallable[BattleFrameRoboticsData] {
|
||||||
("unk3" | uint4) ::
|
("unk3" | uint4) ::
|
||||||
("show_bfr_shield" | bool) ::
|
("show_bfr_shield" | bool) ::
|
||||||
("unk4" | bool) ::
|
("unk4" | bool) ::
|
||||||
optional(bool, target = "inventory" | MountableInventory.custom_inventory_codec(pos.vel.isDefined, VehicleFormat.BattleframeFlight))
|
("inventory" | optional(bool, MountableInventory.custom_inventory_codec(pos.vel.isDefined, VehicleFormat.BattleframeFlight)))
|
||||||
}
|
}
|
||||||
).exmap[BattleFrameRoboticsData] (
|
).exmap[BattleFrameRoboticsData] (
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,7 @@ object CaptureFlagData extends Marshallable[CaptureFlagData] {
|
||||||
("targetBaseGuid" | uint8L) ::
|
("targetBaseGuid" | uint8L) ::
|
||||||
uint8L ::
|
uint8L ::
|
||||||
("milliseconds_remaining" | uint32L) ::
|
("milliseconds_remaining" | uint32L) ::
|
||||||
uint(1)
|
uint(bits = 1)
|
||||||
).exmap[CaptureFlagData](
|
).exmap[CaptureFlagData](
|
||||||
{
|
{
|
||||||
case pos :: faction :: false :: 4 :: 0 :: owningBaseGuid :: 0 :: targetBaseGuid :: 0 :: milliseconds_remaining :: 0 :: HNil =>
|
case pos :: faction :: false :: 4 :: 0 :: owningBaseGuid :: 0 :: targetBaseGuid :: 0 :: milliseconds_remaining :: 0 :: HNil =>
|
||||||
|
|
|
||||||
|
|
@ -406,7 +406,7 @@ object CharacterAppearanceData extends Marshallable[CharacterAppearanceData] {
|
||||||
("unk6" | bool) :: //stream misalignment when set
|
("unk6" | bool) :: //stream misalignment when set
|
||||||
("charging_pose" | bool) ::
|
("charging_pose" | bool) ::
|
||||||
("unk7" | bool) :: //alternate charging pose?
|
("unk7" | bool) :: //alternate charging pose?
|
||||||
optional(bool, "on_zipline" | zipline_codec)
|
("on_zipline" | optional(bool, zipline_codec))
|
||||||
).exmap[CharacterAppearanceB](
|
).exmap[CharacterAppearanceB](
|
||||||
{
|
{
|
||||||
case outfit_id :: outfit :: logo :: u1 :: bpack :: u2 :: u3 :: u4 :: facingPitch :: facingYawUpper :: lfs :: gstate :: cloaking :: u5 :: u6 :: charging :: u7 :: zipline :: HNil =>
|
case outfit_id :: outfit :: logo :: u1 :: bpack :: u2 :: u3 :: u4 :: facingPitch :: facingYawUpper :: lfs :: gstate :: cloaking :: u5 :: u6 :: charging :: u7 :: zipline :: HNil =>
|
||||||
|
|
@ -493,5 +493,5 @@ object CharacterAppearanceData extends Marshallable[CharacterAppearanceData] {
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
implicit val codec: Codec[CharacterAppearanceData] = codec(0)
|
implicit val codec: Codec[CharacterAppearanceData] = codec(name_padding = 0)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,13 +18,13 @@ import shapeless.{::, HNil}
|
||||||
object ImplantEffects extends Enumeration {
|
object ImplantEffects extends Enumeration {
|
||||||
type Type = Value
|
type Type = Value
|
||||||
|
|
||||||
val SurgeEffects = Value(9)
|
val SurgeEffects: ImplantEffects.Value = Value(9)
|
||||||
val PersonalShieldEffects = Value(5)
|
val PersonalShieldEffects: ImplantEffects.Value = Value(5)
|
||||||
val DarklightEffects = Value(3)
|
val DarklightEffects: ImplantEffects.Value = Value(3)
|
||||||
val RegenEffects = Value(0)
|
val RegenEffects: ImplantEffects.Value = Value(0)
|
||||||
val NoEffects = Value(1)
|
val NoEffects: ImplantEffects.Value = Value(1)
|
||||||
|
|
||||||
implicit val codec = PacketHelpers.createEnumerationCodec(this, uint4L)
|
implicit val codec: Codec[ImplantEffects.Value] = PacketHelpers.createEnumerationCodec(this, uint4L)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -120,9 +120,9 @@ object CharacterData extends Marshallable[CharacterData] {
|
||||||
("armor" | uint8L) ::
|
("armor" | uint8L) ::
|
||||||
(("uniform_upgrade" | UniformStyle.codec) >>:~ { style =>
|
(("uniform_upgrade" | UniformStyle.codec) >>:~ { style =>
|
||||||
uint(bits = 3) :: //uniform_upgrade is actually interpreted as a 6u field, but the lower 3u seems to be discarded
|
uint(bits = 3) :: //uniform_upgrade is actually interpreted as a 6u field, but the lower 3u seems to be discarded
|
||||||
("command_rank" | uintL(3)) ::
|
("command_rank" | uint(bits = 3)) ::
|
||||||
listOfN(uint2, "implant_effects" | ImplantEffects.codec) ::
|
("implant_effects" | listOfN(uint2, ImplantEffects.codec)) ::
|
||||||
("cosmetics" | conditional(BattleRank.showCosmetics(style), Cosmetic.codec))
|
("cosmetics" | conditional(BattleRank.showCosmetics(style), Cosmetic.codec))
|
||||||
})
|
})
|
||||||
).exmap[CharacterData](
|
).exmap[CharacterData](
|
||||||
{
|
{
|
||||||
|
|
@ -158,24 +158,24 @@ object CharacterData extends Marshallable[CharacterData] {
|
||||||
def codec_seated(is_backpack: Boolean): Codec[CharacterData] =
|
def codec_seated(is_backpack: Boolean): Codec[CharacterData] =
|
||||||
(
|
(
|
||||||
("uniform_upgrade" | UniformStyle.codec) >>:~ { style =>
|
("uniform_upgrade" | UniformStyle.codec) >>:~ { style =>
|
||||||
uint(3) :: //uniform_upgrade is actually interpreted as a 6u field, but the lower 3u seems to be discarded
|
uint(bits = 3) :: //uniform_upgrade is actually interpreted as a 6u field, but the lower 3u seems to be discarded
|
||||||
("command_rank" | uintL(3)) ::
|
("command_rank" | uintL(bits = 3)) ::
|
||||||
listOfN(uint2, "implant_effects" | ImplantEffects.codec) ::
|
("implant_effects" | listOfN(uint2, ImplantEffects.codec)) ::
|
||||||
("cosmetics" | conditional(BattleRank.showCosmetics(style), Cosmetic.codec))
|
("cosmetics" | conditional(BattleRank.showCosmetics(style), Cosmetic.codec))
|
||||||
}
|
}
|
||||||
).exmap[CharacterData](
|
).exmap[CharacterData](
|
||||||
{
|
{
|
||||||
case uniform :: unk :: cr :: implant_effects :: cosmetics :: HNil =>
|
case uniform :: unk :: cr :: implant_effects :: cosmetics :: HNil =>
|
||||||
Attempt.Successful(
|
Attempt.Successful(
|
||||||
new CharacterData(
|
new CharacterData(
|
||||||
100,
|
health = 100,
|
||||||
0,
|
armor = 0,
|
||||||
uniform,
|
uniform,
|
||||||
unk,
|
unk,
|
||||||
cr,
|
cr,
|
||||||
implant_effects,
|
implant_effects,
|
||||||
cosmetics
|
cosmetics
|
||||||
)(is_backpack, true)
|
)(is_backpack, is_seated = true)
|
||||||
)
|
)
|
||||||
|
|
||||||
case _ =>
|
case _ =>
|
||||||
|
|
@ -195,5 +195,5 @@ object CharacterData extends Marshallable[CharacterData] {
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
implicit val codec: Codec[CharacterData] = codec(false)
|
implicit val codec: Codec[CharacterData] = codec(is_backpack = false)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -75,19 +75,19 @@ object CommonFieldData extends Marshallable[CommonFieldData] {
|
||||||
* @return a `CommonFieldData` object
|
* @return a `CommonFieldData` object
|
||||||
*/
|
*/
|
||||||
def apply(): CommonFieldData =
|
def apply(): CommonFieldData =
|
||||||
CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, false, None, false, None, None, PlanetSideGUID(0))
|
CommonFieldData(PlanetSideEmpire.NEUTRAL, bops = false, alternate = false, v1 = false, None, jammered = false, None, None, PlanetSideGUID(0))
|
||||||
|
|
||||||
def apply(faction: PlanetSideEmpire.Value): CommonFieldData =
|
def apply(faction: PlanetSideEmpire.Value): CommonFieldData =
|
||||||
CommonFieldData(faction, false, false, false, None, false, None, None, PlanetSideGUID(0))
|
CommonFieldData(faction, bops = false, alternate = false, v1 = false, None, jammered = false, None, None, PlanetSideGUID(0))
|
||||||
|
|
||||||
def apply(faction: PlanetSideEmpire.Value, unk: Int): CommonFieldData =
|
def apply(faction: PlanetSideEmpire.Value, unk: Int): CommonFieldData =
|
||||||
CommonFieldData(faction, false, false, unk > 1, None, unk > 0, None, None, PlanetSideGUID(0))
|
CommonFieldData(faction, bops = false, alternate = false, v1 = unk > 1, None, jammered = unk > 0, None, None, PlanetSideGUID(0))
|
||||||
|
|
||||||
def apply(faction: PlanetSideEmpire.Value, unk: Int, player_guid: PlanetSideGUID): CommonFieldData =
|
def apply(faction: PlanetSideEmpire.Value, unk: Int, player_guid: PlanetSideGUID): CommonFieldData =
|
||||||
CommonFieldData(faction, false, false, unk > 1, None, unk > 0, None, None, player_guid)
|
CommonFieldData(faction, bops = false, alternate = false, v1 = unk > 1, None, jammered = unk > 0, None, None, player_guid)
|
||||||
|
|
||||||
def apply(faction: PlanetSideEmpire.Value, destroyed: Boolean, unk: Int): CommonFieldData =
|
def apply(faction: PlanetSideEmpire.Value, destroyed: Boolean, unk: Int): CommonFieldData =
|
||||||
CommonFieldData(faction, false, destroyed, unk > 1, None, unk > 0, None, None, PlanetSideGUID(0))
|
CommonFieldData(faction, bops = false, alternate = destroyed, v1 = unk > 1, None, jammered = unk > 0, None, None, PlanetSideGUID(0))
|
||||||
|
|
||||||
def apply(
|
def apply(
|
||||||
faction: PlanetSideEmpire.Value,
|
faction: PlanetSideEmpire.Value,
|
||||||
|
|
@ -95,7 +95,7 @@ object CommonFieldData extends Marshallable[CommonFieldData] {
|
||||||
unk: Int,
|
unk: Int,
|
||||||
player_guid: PlanetSideGUID
|
player_guid: PlanetSideGUID
|
||||||
): CommonFieldData =
|
): CommonFieldData =
|
||||||
CommonFieldData(faction, false, destroyed, unk > 1, None, unk % 1 == 1, None, None, player_guid)
|
CommonFieldData(faction, bops = false, alternate = destroyed, v1 = unk > 1, None, jammered = false/*unk % 1 == 1*/, None, None, player_guid)
|
||||||
|
|
||||||
def apply(
|
def apply(
|
||||||
faction: PlanetSideEmpire.Value,
|
faction: PlanetSideEmpire.Value,
|
||||||
|
|
@ -107,7 +107,7 @@ object CommonFieldData extends Marshallable[CommonFieldData] {
|
||||||
): CommonFieldData = {
|
): CommonFieldData = {
|
||||||
val jammeredField = if (jammered) { Some(0) }
|
val jammeredField = if (jammered) { Some(0) }
|
||||||
else { None }
|
else { None }
|
||||||
CommonFieldData(faction, bops, destroyed, unk > 1, None, unk % 1 == 1, None, jammeredField, player_guid)
|
CommonFieldData(faction, bops, destroyed, unk > 1, None, jammered = false/*unk % 1 == 1*/, None, jammeredField, player_guid)
|
||||||
}
|
}
|
||||||
|
|
||||||
def codec(extra: Boolean): Codec[CommonFieldData] =
|
def codec(extra: Boolean): Codec[CommonFieldData] =
|
||||||
|
|
@ -116,9 +116,9 @@ object CommonFieldData extends Marshallable[CommonFieldData] {
|
||||||
("bops" | bool) ::
|
("bops" | bool) ::
|
||||||
("alternate" | bool) ::
|
("alternate" | bool) ::
|
||||||
("v1" | bool) :: //the purpose of this bit changes depending on the previous bit
|
("v1" | bool) :: //the purpose of this bit changes depending on the previous bit
|
||||||
conditional(extra, "v2" | CommonFieldDataExtra.codec(unk1 = false)) ::
|
("v2" | conditional(extra, CommonFieldDataExtra.codec(unk1 = false))) ::
|
||||||
("jammered" | bool) ::
|
("jammered" | bool) ::
|
||||||
optional(bool, "v5" | uint16L) ::
|
("v5" | optional(bool, uint16L)) ::
|
||||||
("guid" | PlanetSideGUID.codec)
|
("guid" | PlanetSideGUID.codec)
|
||||||
).xmap[CommonFieldData](
|
).xmap[CommonFieldData](
|
||||||
{
|
{
|
||||||
|
|
@ -139,9 +139,9 @@ object CommonFieldData extends Marshallable[CommonFieldData] {
|
||||||
("bops" | bool) ::
|
("bops" | bool) ::
|
||||||
("alternate" | bool) ::
|
("alternate" | bool) ::
|
||||||
("v1" | bool) :: //though the code path differs depending on the previous bit, this one gets read one way or another
|
("v1" | bool) :: //though the code path differs depending on the previous bit, this one gets read one way or another
|
||||||
conditional(extra, codec = "v2" | CommonFieldDataExtra.codec(unk1 = false)) ::
|
("v2" | conditional(extra, CommonFieldDataExtra.codec(unk1 = false))) ::
|
||||||
("jammered" | bool) ::
|
("jammered" | bool) ::
|
||||||
optional(bool, "v5" | uint16L) ::
|
("v5" | optional(bool, uint16L)) ::
|
||||||
("v4" | bool) ::
|
("v4" | bool) ::
|
||||||
("guid" | PlanetSideGUID.codec)
|
("guid" | PlanetSideGUID.codec)
|
||||||
).exmap[CommonFieldData](
|
).exmap[CommonFieldData](
|
||||||
|
|
@ -158,5 +158,5 @@ object CommonFieldData extends Marshallable[CommonFieldData] {
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
val codec2: Codec[CommonFieldData] = codec2(false)
|
val codec2: Codec[CommonFieldData] = codec2(extra = false)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,7 @@ object DetailedAmmoBoxData extends Marshallable[DetailedAmmoBoxData] {
|
||||||
|
|
||||||
def apply(unk: Int, mag: Int): DetailedAmmoBoxData = {
|
def apply(unk: Int, mag: Int): DetailedAmmoBoxData = {
|
||||||
DetailedAmmoBoxData(
|
DetailedAmmoBoxData(
|
||||||
CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, unk > 0, None, false, None, None, PlanetSideGUID(0)),
|
CommonFieldData(PlanetSideEmpire.NEUTRAL, bops = false, alternate = false, v1 = unk > 0, None, jammered = false, None, None, PlanetSideGUID(0)),
|
||||||
mag
|
mag
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ final case class ImplantEntry(implant: ImplantType, initialization: Option[Int],
|
||||||
extends StreamBitSize {
|
extends StreamBitSize {
|
||||||
override def bitsize: Long = {
|
override def bitsize: Long = {
|
||||||
val timerSize = initialization match {
|
val timerSize = initialization match {
|
||||||
case Some(_) => 8L;
|
case Some(_) => 8L
|
||||||
case None => 1L
|
case None => 1L
|
||||||
}
|
}
|
||||||
9L + timerSize
|
9L + timerSize
|
||||||
|
|
@ -271,7 +271,7 @@ object DetailedCharacterData extends Marshallable[DetailedCharacterData] {
|
||||||
private val implant_entry_codec: Codec[ImplantEntry] = (
|
private val implant_entry_codec: Codec[ImplantEntry] = (
|
||||||
("implant" | uint8L) ::
|
("implant" | uint8L) ::
|
||||||
(bool >>:~ { guard =>
|
(bool >>:~ { guard =>
|
||||||
newcodecs.binary_choice(guard, uint(1), uint8L).hlist
|
newcodecs.binary_choice(guard, uint(bits = 1), uint8L).hlist
|
||||||
})
|
})
|
||||||
).xmap[ImplantEntry](
|
).xmap[ImplantEntry](
|
||||||
{
|
{
|
||||||
|
|
@ -305,7 +305,7 @@ object DetailedCharacterData extends Marshallable[DetailedCharacterData] {
|
||||||
(
|
(
|
||||||
uint8 >>:~ { size =>
|
uint8 >>:~ { size =>
|
||||||
conditional(size > 0, dcd_extra1_codec(padFunc(size))) ::
|
conditional(size > 0, dcd_extra1_codec(padFunc(size))) ::
|
||||||
PacketHelpers.listOfNSized(size - 1, dcd_extra1_codec(0))
|
PacketHelpers.listOfNSized(size - 1, dcd_extra1_codec(pad = 0))
|
||||||
}
|
}
|
||||||
).xmap[List[DCDExtra1]](
|
).xmap[List[DCDExtra1]](
|
||||||
{
|
{
|
||||||
|
|
@ -376,7 +376,7 @@ object DetailedCharacterData extends Marshallable[DetailedCharacterData] {
|
||||||
* `Codec` for a `ImprintingProgress` object.
|
* `Codec` for a `ImprintingProgress` object.
|
||||||
*/
|
*/
|
||||||
private val imprint_progress_codec: Codec[ImprintingProgress] = (
|
private val imprint_progress_codec: Codec[ImprintingProgress] = (
|
||||||
uint(5) ::
|
uint(bits = 5) ::
|
||||||
uint8L
|
uint8L
|
||||||
).as[ImprintingProgress]
|
).as[ImprintingProgress]
|
||||||
|
|
||||||
|
|
@ -464,7 +464,7 @@ object DetailedCharacterData extends Marshallable[DetailedCharacterData] {
|
||||||
def paddingCalculations(contextOffset: Option[Int], implants: List[ImplantEntry], prevLists: List[List[Any]])(
|
def paddingCalculations(contextOffset: Option[Int], implants: List[ImplantEntry], prevLists: List[List[Any]])(
|
||||||
currListLen: Long
|
currListLen: Long
|
||||||
): Int = {
|
): Int = {
|
||||||
paddingCalculations(3, contextOffset, implants, prevLists)(currListLen)
|
paddingCalculations(base = 3, contextOffset, implants, prevLists)(currListLen)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -532,9 +532,9 @@ object DetailedCharacterData extends Marshallable[DetailedCharacterData] {
|
||||||
("stamina" | uint16L) ::
|
("stamina" | uint16L) ::
|
||||||
conditional(suit == ExoSuitType.MAX, uint32L) ::
|
conditional(suit == ExoSuitType.MAX, uint32L) ::
|
||||||
("unk6" | uint16L) ::
|
("unk6" | uint16L) ::
|
||||||
("unk7" | uint(3)) ::
|
("unk7" | uint(bits = 3)) ::
|
||||||
("unk8" | uint32L) ::
|
("unk8" | uint32L) ::
|
||||||
("unk9" | PacketHelpers.listOfNSized(6, uint16L)) :: //always length of 6
|
("unk9" | PacketHelpers.listOfNSized(size = 6, uint16L)) :: //always length of 6
|
||||||
("certs" | listOfN(uint8L, Certification.codec))
|
("certs" | listOfN(uint8L, Certification.codec))
|
||||||
).exmap[DetailedCharacterA](
|
).exmap[DetailedCharacterA](
|
||||||
{
|
{
|
||||||
|
|
@ -591,7 +591,7 @@ object DetailedCharacterData extends Marshallable[DetailedCharacterData] {
|
||||||
|
|
||||||
def b_codec(bep: Long, pad_length: Option[Int]): Codec[DetailedCharacterB] =
|
def b_codec(bep: Long, pad_length: Option[Int]): Codec[DetailedCharacterB] =
|
||||||
(
|
(
|
||||||
optional(bool, "unk1" | uint32L) ::
|
("unk1" | optional(bool, uint32L)) ::
|
||||||
(("implants" | PacketHelpers.listOfNSized(
|
(("implants" | PacketHelpers.listOfNSized(
|
||||||
BattleRank.withExperience(bep).implantSlots,
|
BattleRank.withExperience(bep).implantSlots,
|
||||||
implant_entry_codec
|
implant_entry_codec
|
||||||
|
|
@ -607,17 +607,17 @@ object DetailedCharacterData extends Marshallable[DetailedCharacterData] {
|
||||||
("unk6" | uint32L) ::
|
("unk6" | uint32L) ::
|
||||||
("unk7" | uint32L) ::
|
("unk7" | uint32L) ::
|
||||||
("unk8" | uint32L) ::
|
("unk8" | uint32L) ::
|
||||||
(optional(isFalse, "imprinting" | imprint_progress_codec) >>:~ { imprinting =>
|
(("imprinting" | optional(isFalse, imprint_progress_codec)) >>:~ { imprinting =>
|
||||||
("unkA" | listOfN(uint16L, uint32L)) ::
|
("unkA" | listOfN(uint16L, uint32L)) ::
|
||||||
("unkB" | unkBCodec(
|
("unkB" | unkBCodec(
|
||||||
paddingCalculations(
|
paddingCalculations(
|
||||||
displaceByOptionTest(pad_length, imprinting, 5),
|
displaceByOptionTest(pad_length, imprinting, value = 5),
|
||||||
implants,
|
implants,
|
||||||
List(imprinting.toList, tut, fte, unk3, unk2)
|
List(imprinting.toList, tut, fte, unk3, unk2)
|
||||||
)
|
)
|
||||||
)) ::
|
)) ::
|
||||||
("unkC" | bool) ::
|
("unkC" | bool) ::
|
||||||
conditional(bep >= BattleRank.BR24.experience, "cosmetics" | Cosmetic.codec)
|
("cosmetics" | conditional(bep >= BattleRank.BR24.experience, Cosmetic.codec))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ object DetailedConstructionToolData extends Marshallable[DetailedConstructionToo
|
||||||
def apply(data: CommonFieldData): DetailedConstructionToolData = DetailedConstructionToolData(data, 0)
|
def apply(data: CommonFieldData): DetailedConstructionToolData = DetailedConstructionToolData(data, 0)
|
||||||
|
|
||||||
implicit val codec: Codec[DetailedConstructionToolData] = (
|
implicit val codec: Codec[DetailedConstructionToolData] = (
|
||||||
("data" | CommonFieldData.codec(false)) ::
|
("data" | CommonFieldData.codec(extra = false)) ::
|
||||||
uint8 :: //n > 1 produces a stack of construction items (tends to crash the client)
|
uint8 :: //n > 1 produces a stack of construction items (tends to crash the client)
|
||||||
("mode" | uint16) ::
|
("mode" | uint16) ::
|
||||||
uint2 ::
|
uint2 ::
|
||||||
|
|
|
||||||
|
|
@ -72,7 +72,7 @@ object DetailedPlayerData extends Marshallable[DetailedPlayerData] {
|
||||||
drawn_slot: DrawnSlot.Value
|
drawn_slot: DrawnSlot.Value
|
||||||
): DetailedPlayerData = {
|
): DetailedPlayerData = {
|
||||||
val appearance = basic_appearance(5)
|
val appearance = basic_appearance(5)
|
||||||
DetailedPlayerData(None, appearance, character_data(appearance.altModelBit), Some(inventory), drawn_slot)(false)
|
DetailedPlayerData(None, appearance, character_data(appearance.altModelBit), Some(inventory), drawn_slot)(position_defined = false)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -91,7 +91,7 @@ object DetailedPlayerData extends Marshallable[DetailedPlayerData] {
|
||||||
drawn_slot: DrawnSlot.Value
|
drawn_slot: DrawnSlot.Value
|
||||||
): DetailedPlayerData = {
|
): DetailedPlayerData = {
|
||||||
val appearance = basic_appearance(5)
|
val appearance = basic_appearance(5)
|
||||||
DetailedPlayerData(None, appearance, character_data(appearance.altModelBit), None, drawn_slot)(false)
|
DetailedPlayerData(None, appearance, character_data(appearance.altModelBit), None, drawn_slot)(position_defined = false)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -113,7 +113,7 @@ object DetailedPlayerData extends Marshallable[DetailedPlayerData] {
|
||||||
drawn_slot: DrawnSlot.Value
|
drawn_slot: DrawnSlot.Value
|
||||||
): DetailedPlayerData = {
|
): DetailedPlayerData = {
|
||||||
val appearance = basic_appearance(PlayerData.PaddingOffset(Some(pos)))
|
val appearance = basic_appearance(PlayerData.PaddingOffset(Some(pos)))
|
||||||
DetailedPlayerData(Some(pos), appearance, character_data(appearance.altModelBit), Some(inventory), drawn_slot)(true)
|
DetailedPlayerData(Some(pos), appearance, character_data(appearance.altModelBit), Some(inventory), drawn_slot)(position_defined = true)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -133,14 +133,14 @@ object DetailedPlayerData extends Marshallable[DetailedPlayerData] {
|
||||||
drawn_slot: DrawnSlot.Value
|
drawn_slot: DrawnSlot.Value
|
||||||
): DetailedPlayerData = {
|
): DetailedPlayerData = {
|
||||||
val appearance = basic_appearance(PlayerData.PaddingOffset(Some(pos)))
|
val appearance = basic_appearance(PlayerData.PaddingOffset(Some(pos)))
|
||||||
DetailedPlayerData(Some(pos), appearance, character_data(appearance.altModelBit), None, drawn_slot)(true)
|
DetailedPlayerData(Some(pos), appearance, character_data(appearance.altModelBit), None, drawn_slot)(position_defined = true)
|
||||||
}
|
}
|
||||||
|
|
||||||
def codec(position_defined: Boolean): Codec[DetailedPlayerData] =
|
def codec(position_defined: Boolean): Codec[DetailedPlayerData] =
|
||||||
(conditional(position_defined, "pos" | PlacementData.codec) >>:~ { pos =>
|
(conditional(position_defined, "pos" | PlacementData.codec) >>:~ { pos =>
|
||||||
("basic_appearance" | CharacterAppearanceData.codec(PlayerData.PaddingOffset(pos))) >>:~ { app =>
|
("basic_appearance" | CharacterAppearanceData.codec(PlayerData.PaddingOffset(pos))) >>:~ { app =>
|
||||||
("character_data" | DetailedCharacterData.codec(app.a.exosuit, app.altModelBit)) ::
|
("character_data" | DetailedCharacterData.codec(app.a.exosuit, app.altModelBit)) ::
|
||||||
optional(bool, "inventory" | InventoryData.codec_detailed) ::
|
("inventory" | optional(bool, InventoryData.codec_detailed)) ::
|
||||||
("drawn_slot" | DrawnSlot.codec) ::
|
("drawn_slot" | DrawnSlot.codec) ::
|
||||||
bool //usually false
|
bool //usually false
|
||||||
}
|
}
|
||||||
|
|
@ -155,5 +155,5 @@ object DetailedPlayerData extends Marshallable[DetailedPlayerData] {
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
implicit val codec: Codec[DetailedPlayerData] = codec(false)
|
implicit val codec: Codec[DetailedPlayerData] = codec(position_defined = false)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ object DetailedREKData extends Marshallable[DetailedREKData] {
|
||||||
uint16L ::
|
uint16L ::
|
||||||
uint4L ::
|
uint4L ::
|
||||||
("unk" | uint8) ::
|
("unk" | uint8) ::
|
||||||
uint(7)
|
uint(bits = 7)
|
||||||
).exmap[DetailedREKData](
|
).exmap[DetailedREKData](
|
||||||
{
|
{
|
||||||
case data :: 2 :: 0 :: 8 :: unk :: 0 :: HNil =>
|
case data :: 2 :: 0 :: 8 :: unk :: 0 :: HNil =>
|
||||||
|
|
|
||||||
|
|
@ -56,11 +56,11 @@ object DetailedWeaponData extends Marshallable[DetailedWeaponData] {
|
||||||
DetailedWeaponData(
|
DetailedWeaponData(
|
||||||
CommonFieldData(
|
CommonFieldData(
|
||||||
PlanetSideEmpire(unk1 & 3),
|
PlanetSideEmpire(unk1 & 3),
|
||||||
false,
|
bops = false,
|
||||||
false,
|
alternate = false,
|
||||||
(unk2 & 8) == 8,
|
v1 = (unk2 & 8) == 8,
|
||||||
None,
|
None,
|
||||||
(unk2 & 4) == 4,
|
jammered = (unk2 & 4) == 4,
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
PlanetSideGUID(0)
|
PlanetSideGUID(0)
|
||||||
|
|
@ -92,11 +92,11 @@ object DetailedWeaponData extends Marshallable[DetailedWeaponData] {
|
||||||
DetailedWeaponData(
|
DetailedWeaponData(
|
||||||
CommonFieldData(
|
CommonFieldData(
|
||||||
PlanetSideEmpire(unk1 & 3),
|
PlanetSideEmpire(unk1 & 3),
|
||||||
false,
|
bops = false,
|
||||||
false,
|
alternate = false,
|
||||||
(unk2 & 8) == 8,
|
v1 = (unk2 & 8) == 8,
|
||||||
None,
|
None,
|
||||||
(unk2 & 4) == 4,
|
jammered = (unk2 & 4) == 4,
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
PlanetSideGUID(0)
|
PlanetSideGUID(0)
|
||||||
|
|
@ -112,7 +112,7 @@ object DetailedWeaponData extends Marshallable[DetailedWeaponData] {
|
||||||
uint8 ::
|
uint8 ::
|
||||||
("fire_mode" | uint8) ::
|
("fire_mode" | uint8) ::
|
||||||
uint2 ::
|
uint2 ::
|
||||||
optional(bool, "ammo" | InventoryData.codec_detailed) ::
|
("ammo" | optional(bool, InventoryData.codec_detailed)) ::
|
||||||
("unk" | bool)
|
("unk" | bool)
|
||||||
).exmap[DetailedWeaponData](
|
).exmap[DetailedWeaponData](
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -46,9 +46,9 @@ object DroppodData extends Marshallable[DroppodData] {
|
||||||
("basic" | CommonFieldDataWithPlacement.codec) ::
|
("basic" | CommonFieldDataWithPlacement.codec) ::
|
||||||
bool ::
|
bool ::
|
||||||
("health" | uint8L) :: //health
|
("health" | uint8L) :: //health
|
||||||
uintL(5) :: //0x0
|
uintL(bits = 5) :: //0x0
|
||||||
uint4L :: //0xF
|
uint4L :: //0xF
|
||||||
uintL(6) :: //0x0
|
uintL(bits = 6) :: //0x0
|
||||||
("boosters" | uint4L) :: //0x9 on standby, 0x0 when burning and occupied (basic.player_guid?)
|
("boosters" | uint4L) :: //0x9 on standby, 0x0 when burning and occupied (basic.player_guid?)
|
||||||
("unk" | bool)
|
("unk" | bool)
|
||||||
).exmap[DroppodData](
|
).exmap[DroppodData](
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@ object HandheldData extends Marshallable[HandheldData] {
|
||||||
implicit val codec: Codec[HandheldData] = (
|
implicit val codec: Codec[HandheldData] = (
|
||||||
("data" | CommonFieldData.codec) ::
|
("data" | CommonFieldData.codec) ::
|
||||||
("mode" | uint8) ::
|
("mode" | uint8) ::
|
||||||
("unk" | uint(3))
|
("unk" | uint(bits = 3))
|
||||||
).exmap[HandheldData](
|
).exmap[HandheldData](
|
||||||
{
|
{
|
||||||
case data :: mode :: unk :: HNil =>
|
case data :: mode :: unk :: HNil =>
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@ object InternalSlot {
|
||||||
* Used for `0x18` `ObjectCreateDetailedMessage` packets
|
* Used for `0x18` `ObjectCreateDetailedMessage` packets
|
||||||
*/
|
*/
|
||||||
val codec_detailed: Codec[InternalSlot] = (
|
val codec_detailed: Codec[InternalSlot] = (
|
||||||
("objectClass" | uintL(11)) >>:~ { obj_cls =>
|
("objectClass" | uintL(bits = 11)) >>:~ { obj_cls =>
|
||||||
("guid" | PlanetSideGUID.codec) ::
|
("guid" | PlanetSideGUID.codec) ::
|
||||||
("parentSlot" | PacketHelpers.encodedStringSize) ::
|
("parentSlot" | PacketHelpers.encodedStringSize) ::
|
||||||
("obj" | ObjectClass.selectDataDetailedCodec(obj_cls)) //it's fine for this call to fail
|
("obj" | ObjectClass.selectDataDetailedCodec(obj_cls)) //it's fine for this call to fail
|
||||||
|
|
@ -57,7 +57,7 @@ object InternalSlot {
|
||||||
* Used for `0x17` `ObjectCreateMessage` packets
|
* Used for `0x17` `ObjectCreateMessage` packets
|
||||||
*/
|
*/
|
||||||
val codec: Codec[InternalSlot] = (
|
val codec: Codec[InternalSlot] = (
|
||||||
("objectClass" | uintL(11)) >>:~ { obj_cls =>
|
("objectClass" | uintL(bits = 11)) >>:~ { obj_cls =>
|
||||||
("guid" | PlanetSideGUID.codec) ::
|
("guid" | PlanetSideGUID.codec) ::
|
||||||
("parentSlot" | PacketHelpers.encodedStringSize) ::
|
("parentSlot" | PacketHelpers.encodedStringSize) ::
|
||||||
("obj" | ObjectClass.selectDataCodec(obj_cls)) //it's fine for this call to fail
|
("obj" | ObjectClass.selectDataCodec(obj_cls)) //it's fine for this call to fail
|
||||||
|
|
|
||||||
|
|
@ -30,10 +30,10 @@ object LargeDeployableData extends Marshallable[LargeDeployableData] {
|
||||||
implicit val codec: Codec[LargeDeployableData] = (
|
implicit val codec: Codec[LargeDeployableData] = (
|
||||||
("deploy" | CommonFieldDataWithPlacement.codec2) ::
|
("deploy" | CommonFieldDataWithPlacement.codec2) ::
|
||||||
("health" | uint8L) ::
|
("health" | uint8L) ::
|
||||||
uintL(7) ::
|
uintL(bits = 7) ::
|
||||||
uint4L ::
|
uint4L ::
|
||||||
uint2L ::
|
uint2L ::
|
||||||
optional(bool, "internals" | InventoryData.codec)
|
("internals" | optional(bool, InventoryData.codec))
|
||||||
).exmap[LargeDeployableData](
|
).exmap[LargeDeployableData](
|
||||||
{
|
{
|
||||||
case deploy :: health :: 0 :: 0xf :: 0 :: internals :: HNil =>
|
case deploy :: health :: 0 :: 0xf :: 0 :: internals :: HNil =>
|
||||||
|
|
|
||||||
|
|
@ -31,9 +31,11 @@ object LockerContainerData extends Marshallable[LockerContainerData] {
|
||||||
new LockerContainerData(Some(InventoryData(inventory)))
|
new LockerContainerData(Some(InventoryData(inventory)))
|
||||||
|
|
||||||
implicit val codec: Codec[LockerContainerData] = (
|
implicit val codec: Codec[LockerContainerData] = (
|
||||||
uint32 :: uint32 :: uint(17) ::
|
uint32 ::
|
||||||
|
uint32 ::
|
||||||
|
uint(bits = 17) ::
|
||||||
uint2L ::
|
uint2L ::
|
||||||
uint(21) ::
|
uint(bits = 21) ::
|
||||||
("inventory" | optional(bool, InventoryData.codec))
|
("inventory" | optional(bool, InventoryData.codec))
|
||||||
).exmap[LockerContainerData](
|
).exmap[LockerContainerData](
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1216,22 +1216,21 @@ object ObjectClass {
|
||||||
case ObjectClass.advanced_ace => DroppedItemData(HandheldData.codec, "advanced ace")
|
case ObjectClass.advanced_ace => DroppedItemData(HandheldData.codec, "advanced ace")
|
||||||
case ObjectClass.router_telepad => DroppedItemData(HandheldData.codec, "router telepad")
|
case ObjectClass.router_telepad => DroppedItemData(HandheldData.codec, "router telepad")
|
||||||
case ObjectClass.boomer_trigger => DroppedItemData(HandheldData.codec, "boomer trigger")
|
case ObjectClass.boomer_trigger => DroppedItemData(HandheldData.codec, "boomer trigger")
|
||||||
case ObjectClass.boomer => ConstructorData(CommonFieldDataWithPlacement.codec2, "ace deployable")
|
case ObjectClass.boomer => ConstructorData(CommonFieldDataWithPlacement.codec, "ace deployable")
|
||||||
case ObjectClass.he_mine => ConstructorData(CommonFieldDataWithPlacement.codec2, "ace deployable")
|
case ObjectClass.he_mine => ConstructorData(CommonFieldDataWithPlacement.codec, "ace deployable")
|
||||||
case ObjectClass.jammer_mine => ConstructorData(CommonFieldDataWithPlacement.codec2, "ace deployable")
|
case ObjectClass.jammer_mine => ConstructorData(CommonFieldDataWithPlacement.codec, "ace deployable")
|
||||||
case ObjectClass.motionalarmsensor => ConstructorData(CommonFieldDataWithPlacement.codec2, "ace deployable")
|
case ObjectClass.motionalarmsensor => ConstructorData(CommonFieldDataWithPlacement.codec, "ace deployable")
|
||||||
case ObjectClass.sensor_shield => ConstructorData(CommonFieldDataWithPlacement.codec2, "ace deployable")
|
case ObjectClass.sensor_shield => ConstructorData(CommonFieldDataWithPlacement.codec, "ace deployable")
|
||||||
case ObjectClass.spitfire_aa => ConstructorData(SmallTurretData.codec, "small turret")
|
case ObjectClass.spitfire_aa => ConstructorData(SmallTurretData.codec, "small turret")
|
||||||
case ObjectClass.spitfire_cloaked => ConstructorData(SmallTurretData.codec, "small turret")
|
case ObjectClass.spitfire_cloaked => ConstructorData(SmallTurretData.codec, "small turret")
|
||||||
case ObjectClass.spitfire_turret => ConstructorData(SmallTurretData.codec, "small turret")
|
case ObjectClass.spitfire_turret => ConstructorData(SmallTurretData.codec, "small turret")
|
||||||
case ObjectClass.tank_traps => ConstructorData(TRAPData.codec, "trap")
|
case ObjectClass.tank_traps => ConstructorData(TRAPData.codec, "trap")
|
||||||
case ObjectClass.deployable_shield_generator =>
|
case ObjectClass.deployable_shield_generator => ConstructorData(AegisShieldGeneratorData.codec, "shield generator")
|
||||||
ConstructorData(AegisShieldGeneratorData.codec, "shield generator")
|
case ObjectClass.portable_manned_turret => ConstructorData(OneMannedFieldTurretData.codec, "field turret")
|
||||||
case ObjectClass.portable_manned_turret => ConstructorData(OneMannedFieldTurretData.codec, "field turret")
|
case ObjectClass.portable_manned_turret_nc => ConstructorData(OneMannedFieldTurretData.codec, "field turret")
|
||||||
case ObjectClass.portable_manned_turret_nc => ConstructorData(OneMannedFieldTurretData.codec, "field turret")
|
case ObjectClass.portable_manned_turret_tr => ConstructorData(OneMannedFieldTurretData.codec, "field turret")
|
||||||
case ObjectClass.portable_manned_turret_tr => ConstructorData(OneMannedFieldTurretData.codec, "field turret")
|
case ObjectClass.portable_manned_turret_vs => ConstructorData(OneMannedFieldTurretData.codec, "field turret")
|
||||||
case ObjectClass.portable_manned_turret_vs => ConstructorData(OneMannedFieldTurretData.codec, "field turret")
|
case ObjectClass.router_telepad_deployable => DroppedItemData(TelepadDeployableData.codec, "telepad deployable")
|
||||||
case ObjectClass.router_telepad_deployable => DroppedItemData(TelepadDeployableData.codec, "telepad deployable")
|
|
||||||
//projectiles
|
//projectiles
|
||||||
case ObjectClass.aphelion_plasma_cloud => ConstructorData(RadiationCloudData.codec, "radiation cloud")
|
case ObjectClass.aphelion_plasma_cloud => ConstructorData(RadiationCloudData.codec, "radiation cloud")
|
||||||
case ObjectClass.aphelion_starfire_projectile => ConstructorData(RemoteProjectileData.codec, "projectile")
|
case ObjectClass.aphelion_starfire_projectile => ConstructorData(RemoteProjectileData.codec, "projectile")
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,6 @@ final case class OneMannedFieldTurretData(
|
||||||
}
|
}
|
||||||
|
|
||||||
object OneMannedFieldTurretData extends Marshallable[OneMannedFieldTurretData] {
|
object OneMannedFieldTurretData extends Marshallable[OneMannedFieldTurretData] {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Overloaded constructor that mandates information about the internal weapon of the field turret.
|
* Overloaded constructor that mandates information about the internal weapon of the field turret.
|
||||||
* @param deploy data common to objects spawned by the (advanced) adaptive construction engine
|
* @param deploy data common to objects spawned by the (advanced) adaptive construction engine
|
||||||
|
|
@ -55,10 +54,10 @@ object OneMannedFieldTurretData extends Marshallable[OneMannedFieldTurretData] {
|
||||||
PlanetSideGUID.codec :: //hoist/extract with the deploy.owner_guid in field above
|
PlanetSideGUID.codec :: //hoist/extract with the deploy.owner_guid in field above
|
||||||
bool ::
|
bool ::
|
||||||
("health" | uint8L) ::
|
("health" | uint8L) ::
|
||||||
uint(5) ::
|
uint(bits = 5) ::
|
||||||
uint4 ::
|
uint4 ::
|
||||||
uint2 ::
|
uint2 ::
|
||||||
optional(bool, "internals" | InventoryData.codec)
|
("internals" | optional(bool, InventoryData.codec))
|
||||||
).exmap[OneMannedFieldTurretData](
|
).exmap[OneMannedFieldTurretData](
|
||||||
{
|
{
|
||||||
case deploy :: player :: false :: health :: 0 :: 0xf :: 0 :: internals :: HNil =>
|
case deploy :: player :: false :: health :: 0 :: 0xf :: 0 :: internals :: HNil =>
|
||||||
|
|
|
||||||
|
|
@ -58,9 +58,9 @@ object OrbitalShuttleData extends Marshallable[OrbitalShuttleData] {
|
||||||
|
|
||||||
implicit val codec: Codec[OrbitalShuttleData] = (
|
implicit val codec: Codec[OrbitalShuttleData] = (
|
||||||
("faction" | PlanetSideEmpire.codec) ::
|
("faction" | PlanetSideEmpire.codec) ::
|
||||||
uintL(25) ::
|
uintL(bits = 25) ::
|
||||||
uint8L :: //255
|
uint8L :: //255
|
||||||
uintL(5) ::
|
uintL(bits = 5) ::
|
||||||
uint4L :: //7
|
uint4L :: //7
|
||||||
uint2L
|
uint2L
|
||||||
).exmap[OrbitalShuttleData](
|
).exmap[OrbitalShuttleData](
|
||||||
|
|
|
||||||
|
|
@ -76,7 +76,7 @@ object PlayerData extends Marshallable[PlayerData] {
|
||||||
): PlayerData = {
|
): PlayerData = {
|
||||||
val appearance = basic_appearance(5)
|
val appearance = basic_appearance(5)
|
||||||
PlayerData(None, appearance, character_data(appearance.altModelBit.isDefined, true), Some(inventory), drawn_slot)(
|
PlayerData(None, appearance, character_data(appearance.altModelBit.isDefined, true), Some(inventory), drawn_slot)(
|
||||||
false
|
position_defined = false
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -96,7 +96,7 @@ object PlayerData extends Marshallable[PlayerData] {
|
||||||
drawn_slot: DrawnSlot.Type
|
drawn_slot: DrawnSlot.Type
|
||||||
): PlayerData = {
|
): PlayerData = {
|
||||||
val appearance = basic_appearance(5)
|
val appearance = basic_appearance(5)
|
||||||
PlayerData(None, appearance, character_data(appearance.altModelBit.isDefined, true), None, drawn_slot)(false)
|
PlayerData(None, appearance, character_data(appearance.altModelBit.isDefined, true), None, drawn_slot)(position_defined = false)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -124,7 +124,7 @@ object PlayerData extends Marshallable[PlayerData] {
|
||||||
character_data(appearance.altModelBit.isDefined, false),
|
character_data(appearance.altModelBit.isDefined, false),
|
||||||
Some(inventory),
|
Some(inventory),
|
||||||
drawn_slot
|
drawn_slot
|
||||||
)(true)
|
)(position_defined = true)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -144,7 +144,7 @@ object PlayerData extends Marshallable[PlayerData] {
|
||||||
drawn_slot: DrawnSlot.Type
|
drawn_slot: DrawnSlot.Type
|
||||||
): PlayerData = {
|
): PlayerData = {
|
||||||
val appearance = basic_appearance(PaddingOffset(Some(pos)))
|
val appearance = basic_appearance(PaddingOffset(Some(pos)))
|
||||||
PlayerData(Some(pos), appearance, character_data(appearance.altModelBit.isDefined, false), None, drawn_slot)(true)
|
PlayerData(Some(pos), appearance, character_data(appearance.altModelBit.isDefined, false), None, drawn_slot)(position_defined = true)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -205,7 +205,7 @@ object PlayerData extends Marshallable[PlayerData] {
|
||||||
CharacterData.codec(app.b.backpack),
|
CharacterData.codec(app.b.backpack),
|
||||||
CharacterData.codec_seated(app.b.backpack)
|
CharacterData.codec_seated(app.b.backpack)
|
||||||
)) ::
|
)) ::
|
||||||
optional(bool, "inventory" | InventoryData.codec) ::
|
("inventory" | optional(bool, InventoryData.codec)) ::
|
||||||
("drawn_slot" | DrawnSlot.codec) ::
|
("drawn_slot" | DrawnSlot.codec) ::
|
||||||
bool //usually false
|
bool //usually false
|
||||||
}
|
}
|
||||||
|
|
@ -232,14 +232,14 @@ object PlayerData extends Marshallable[PlayerData] {
|
||||||
(
|
(
|
||||||
("basic_appearance" | CharacterAppearanceData.codec(offset)) >>:~ { app =>
|
("basic_appearance" | CharacterAppearanceData.codec(offset)) >>:~ { app =>
|
||||||
("character_data" | CharacterData.codec_seated(app.b.backpack)) ::
|
("character_data" | CharacterData.codec_seated(app.b.backpack)) ::
|
||||||
optional(bool, "inventory" | InventoryData.codec) ::
|
("inventory" | optional(bool, InventoryData.codec)) ::
|
||||||
("drawn_slot" | DrawnSlot.codec) ::
|
("drawn_slot" | DrawnSlot.codec) ::
|
||||||
bool //usually false
|
bool //usually false
|
||||||
}
|
}
|
||||||
).xmap[PlayerData](
|
).xmap[PlayerData](
|
||||||
{
|
{
|
||||||
case app :: data :: inv :: hand :: _ :: HNil =>
|
case app :: data :: inv :: hand :: _ :: HNil =>
|
||||||
PlayerData(None, app, data, inv, hand)(false)
|
PlayerData(None, app, data, inv, hand)(position_defined = false)
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
case PlayerData(_, app, data, inv, hand) =>
|
case PlayerData(_, app, data, inv, hand) =>
|
||||||
|
|
@ -247,5 +247,5 @@ object PlayerData extends Marshallable[PlayerData] {
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
implicit val codec: Codec[PlayerData] = codec(false)
|
implicit val codec: Codec[PlayerData] = codec(position_defined = false)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ object REKData extends Marshallable[REKData] {
|
||||||
implicit val codec: Codec[REKData] = (
|
implicit val codec: Codec[REKData] = (
|
||||||
("data" | CommonFieldData.codec2) ::
|
("data" | CommonFieldData.codec2) ::
|
||||||
("unk1" | uint16) ::
|
("unk1" | uint16) ::
|
||||||
("unk2" | uint(10))
|
("unk2" | uint(bits = 10))
|
||||||
).exmap[REKData](
|
).exmap[REKData](
|
||||||
{
|
{
|
||||||
case data :: u1 :: u2 :: HNil =>
|
case data :: u1 :: u2 :: HNil =>
|
||||||
|
|
|
||||||
|
|
@ -26,19 +26,19 @@ object FlightPhysics extends Enumeration {
|
||||||
type Type = Value
|
type Type = Value
|
||||||
|
|
||||||
//valid (extremely small distance) (requires non-zero unk4, unk5)
|
//valid (extremely small distance) (requires non-zero unk4, unk5)
|
||||||
val State3 = Value(3)
|
val State3: FlightPhysics.Value = Value(3)
|
||||||
//valid (infinite) (if unk4 == 0 unk5 == 0, minimum distance + time)
|
//valid (infinite) (if unk4 == 0 unk5 == 0, minimum distance + time)
|
||||||
val State4 = Value(4)
|
val State4: FlightPhysics.Value = Value(4)
|
||||||
//valid(infinite)
|
//valid(infinite)
|
||||||
val State5 = Value(5)
|
val State5: FlightPhysics.Value = Value(5)
|
||||||
//valid (uses velocity) (infinite)
|
//valid (uses velocity) (infinite)
|
||||||
val State6 = Value(6)
|
val State6: FlightPhysics.Value = Value(6)
|
||||||
//valid (uses velocity) (infinite)
|
//valid (uses velocity) (infinite)
|
||||||
val State7 = Value(7)
|
val State7: FlightPhysics.Value = Value(7)
|
||||||
//valid (uses velocity) (time > 0 is infinite) (unk5 == 2)
|
//valid (uses velocity) (time > 0 is infinite) (unk5 == 2)
|
||||||
val State15 = Value(15)
|
val State15: FlightPhysics.Value = Value(15)
|
||||||
|
|
||||||
implicit val codec = PacketHelpers.createEnumerationCodec(this, uint4L)
|
implicit val codec: Codec[FlightPhysics.Value] = PacketHelpers.createEnumerationCodec(this, uint4L)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@ final case class SmallTurretData(
|
||||||
case None =>
|
case None =>
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
22L + deploySize + internalSize //8u + 7u + 4u + 2u + 1u
|
23L + deploySize + internalSize //1u + 8u + 7u + 4u + 2u + 1u
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -49,15 +49,16 @@ object SmallTurretData extends Marshallable[SmallTurretData] {
|
||||||
new SmallTurretData(deploy, health, Some(internals))
|
new SmallTurretData(deploy, health, Some(internals))
|
||||||
|
|
||||||
implicit val codec: Codec[SmallTurretData] = (
|
implicit val codec: Codec[SmallTurretData] = (
|
||||||
("deploy" | CommonFieldDataWithPlacement.codec2) ::
|
("deploy" | CommonFieldDataWithPlacement.codec) ::
|
||||||
|
ignore(size = 1) ::
|
||||||
("health" | uint8L) ::
|
("health" | uint8L) ::
|
||||||
uintL(7) ::
|
uintL(bits = 7) ::
|
||||||
uint4L ::
|
uint4L ::
|
||||||
uint2L ::
|
uint2L ::
|
||||||
optional(bool, "internals" | InventoryData.codec)
|
("internals" | optional(bool, InventoryData.codec))
|
||||||
).exmap[SmallTurretData](
|
).exmap[SmallTurretData](
|
||||||
{
|
{
|
||||||
case deploy :: health :: 0 :: 0xf :: 0 :: internals :: HNil =>
|
case deploy :: _ :: health :: 0 :: 0xf :: 0 :: internals :: HNil =>
|
||||||
val (newHealth, newInternals) = if (health == 0 || internals.isEmpty || internals.get.contents.isEmpty) {
|
val (newHealth, newInternals) = if (health == 0 || internals.isEmpty || internals.get.contents.isEmpty) {
|
||||||
(0, None)
|
(0, None)
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -75,7 +76,7 @@ object SmallTurretData extends Marshallable[SmallTurretData] {
|
||||||
} else {
|
} else {
|
||||||
(health, internals)
|
(health, internals)
|
||||||
}
|
}
|
||||||
Attempt.successful(deploy :: newHealth :: 0 :: 0xf :: 0 :: newInternals :: HNil)
|
Attempt.successful(deploy :: () :: newHealth :: 0 :: 0xf :: 0 :: newInternals :: HNil)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,20 +14,21 @@ import shapeless.{::, HNil}
|
||||||
*/
|
*/
|
||||||
final case class TRAPData(deploy: CommonFieldDataWithPlacement, health: Int) extends ConstructorData {
|
final case class TRAPData(deploy: CommonFieldDataWithPlacement, health: Int) extends ConstructorData {
|
||||||
override def bitsize: Long = {
|
override def bitsize: Long = {
|
||||||
22L + deploy.bitsize //8u + 7u + 4u + 3u
|
23L + deploy.bitsize //1u + 8u + 7u + 4u + 3u
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
object TRAPData extends Marshallable[TRAPData] {
|
object TRAPData extends Marshallable[TRAPData] {
|
||||||
implicit val codec: Codec[TRAPData] = (
|
implicit val codec: Codec[TRAPData] = (
|
||||||
("deploy" | CommonFieldDataWithPlacement.codec2) ::
|
("deploy" | CommonFieldDataWithPlacement.codec) ::
|
||||||
|
ignore(size = 1) ::
|
||||||
("health" | uint8L) ::
|
("health" | uint8L) ::
|
||||||
uint(7) ::
|
uint(bits = 7) ::
|
||||||
uint4L ::
|
uint4L ::
|
||||||
uint(3)
|
uint(bits = 3)
|
||||||
).exmap[TRAPData](
|
).exmap[TRAPData](
|
||||||
{
|
{
|
||||||
case deploy :: health :: 0 :: 15 :: 0 :: HNil =>
|
case deploy :: _:: health :: 0 :: 15 :: 0 :: HNil =>
|
||||||
Attempt.successful(TRAPData(deploy, health))
|
Attempt.successful(TRAPData(deploy, health))
|
||||||
|
|
||||||
case data =>
|
case data =>
|
||||||
|
|
@ -35,7 +36,7 @@ object TRAPData extends Marshallable[TRAPData] {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
case TRAPData(deploy, health) =>
|
case TRAPData(deploy, health) =>
|
||||||
Attempt.successful(deploy :: health :: 0 :: 15 :: 0 :: HNil)
|
Attempt.successful(deploy :: () :: health :: 0 :: 15 :: 0 :: HNil)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -106,7 +106,7 @@ object VehicleData extends Marshallable[VehicleData] {
|
||||||
cloak: Boolean,
|
cloak: Boolean,
|
||||||
inventory: Option[InventoryData]
|
inventory: Option[InventoryData]
|
||||||
): VehicleData = {
|
): VehicleData = {
|
||||||
VehicleData(pos, basic, false, health, false, false, driveState, false, false, cloak, None, inventory)(
|
VehicleData(pos, basic, unk3 = false, health, unk4 = false, no_mount_points = false, driveState, unk5 = false, unk6 = false, cloak = cloak, None, inventory)(
|
||||||
VehicleFormat.Normal
|
VehicleFormat.Normal
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -128,7 +128,7 @@ object VehicleData extends Marshallable[VehicleData] {
|
||||||
format: UtilityVehicleData,
|
format: UtilityVehicleData,
|
||||||
inventory: Option[InventoryData]
|
inventory: Option[InventoryData]
|
||||||
): VehicleData = {
|
): VehicleData = {
|
||||||
VehicleData(pos, basic, false, health, false, false, driveState, false, false, cloak, Some(format), inventory)(
|
VehicleData(pos, basic, unk3 = false, health, unk4 = false, no_mount_points = false, driveState, unk5 = false, unk6 = false, cloak = cloak, Some(format), inventory)(
|
||||||
VehicleFormat.Utility
|
VehicleFormat.Utility
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -150,7 +150,7 @@ object VehicleData extends Marshallable[VehicleData] {
|
||||||
format: VariantVehicleData,
|
format: VariantVehicleData,
|
||||||
inventory: Option[InventoryData]
|
inventory: Option[InventoryData]
|
||||||
): VehicleData = {
|
): VehicleData = {
|
||||||
VehicleData(pos, basic, false, health, false, false, driveState, false, false, cloak, Some(format), inventory)(
|
VehicleData(pos, basic, unk3 = false, health, unk4 = false, no_mount_points = false, driveState, unk5 = false, unk6 = false, cloak = cloak, Some(format), inventory)(
|
||||||
VehicleFormat.Variant
|
VehicleFormat.Variant
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -227,8 +227,8 @@ object VehicleData extends Marshallable[VehicleData] {
|
||||||
("unk5" | bool) :: //unknown but generally false; can cause stream misalignment if set when unexpectedly
|
("unk5" | bool) :: //unknown but generally false; can cause stream misalignment if set when unexpectedly
|
||||||
("unk6" | bool) ::
|
("unk6" | bool) ::
|
||||||
("cloak" | bool) :: //cloak as wraith, phantasm
|
("cloak" | bool) :: //cloak as wraith, phantasm
|
||||||
conditional(vehicle_type != VehicleFormat.Normal,"vehicle_format_data" | selectFormatReader(vehicle_type)) ::
|
("vehicle_format_data" | conditional(vehicle_type != VehicleFormat.Normal, selectFormatReader(vehicle_type))) ::
|
||||||
optional(bool, target = "inventory" | MountableInventory.custom_inventory_codec(pos.vel.isDefined, vehicle_type))
|
("inventory" | optional(bool, MountableInventory.custom_inventory_codec(pos.vel.isDefined, vehicle_type)))
|
||||||
}
|
}
|
||||||
).exmap[VehicleData](
|
).exmap[VehicleData](
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -54,8 +54,8 @@ object WeaponData extends Marshallable[WeaponData] {
|
||||||
WeaponData(
|
WeaponData(
|
||||||
CommonFieldData(
|
CommonFieldData(
|
||||||
PlanetSideEmpire(unk1 & 3),
|
PlanetSideEmpire(unk1 & 3),
|
||||||
false,
|
bops = false,
|
||||||
false,
|
alternate = false,
|
||||||
(unk2 & 8) == 8,
|
(unk2 & 8) == 8,
|
||||||
None,
|
None,
|
||||||
(unk2 & 4) == 4,
|
(unk2 & 4) == 4,
|
||||||
|
|
@ -91,8 +91,8 @@ object WeaponData extends Marshallable[WeaponData] {
|
||||||
WeaponData(
|
WeaponData(
|
||||||
CommonFieldData(
|
CommonFieldData(
|
||||||
PlanetSideEmpire(unk1 & 3),
|
PlanetSideEmpire(unk1 & 3),
|
||||||
false,
|
bops = false,
|
||||||
false,
|
alternate = false,
|
||||||
(unk2 & 8) == 8,
|
(unk2 & 8) == 8,
|
||||||
None,
|
None,
|
||||||
(unk2 & 4) == 4,
|
(unk2 & 4) == 4,
|
||||||
|
|
@ -137,8 +137,8 @@ object WeaponData extends Marshallable[WeaponData] {
|
||||||
WeaponData(
|
WeaponData(
|
||||||
CommonFieldData(
|
CommonFieldData(
|
||||||
PlanetSideEmpire(unk1 & 3),
|
PlanetSideEmpire(unk1 & 3),
|
||||||
false,
|
bops = false,
|
||||||
false,
|
alternate = false,
|
||||||
(unk2 & 8) == 8,
|
(unk2 & 8) == 8,
|
||||||
None,
|
None,
|
||||||
(unk2 & 4) == 4,
|
(unk2 & 4) == 4,
|
||||||
|
|
|
||||||
|
|
@ -87,17 +87,6 @@ class AvatarService(zone: Zone) extends Actor {
|
||||||
AvatarResponse.EnvironmentalDamage(player_guid, source_guid, amount)
|
AvatarResponse.EnvironmentalDamage(player_guid, source_guid, amount)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
case AvatarAction.DeployItem(player_guid, item) =>
|
|
||||||
val definition = item.Definition
|
|
||||||
val objectData = definition.Packet.ConstructorData(item).get
|
|
||||||
AvatarEvents.publish(
|
|
||||||
AvatarServiceResponse(
|
|
||||||
s"/$forChannel/Avatar",
|
|
||||||
player_guid,
|
|
||||||
AvatarResponse.DropItem(ObjectCreateMessage(definition.ObjectId, item.GUID, objectData))
|
|
||||||
)
|
|
||||||
)
|
|
||||||
case AvatarAction.Destroy(victim, killer, weapon, pos) =>
|
case AvatarAction.Destroy(victim, killer, weapon, pos) =>
|
||||||
AvatarEvents.publish(
|
AvatarEvents.publish(
|
||||||
AvatarServiceResponse(s"/$forChannel/Avatar", victim, AvatarResponse.Destroy(victim, killer, weapon, pos))
|
AvatarServiceResponse(s"/$forChannel/Avatar", victim, AvatarResponse.Destroy(victim, killer, weapon, pos))
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,6 @@ package net.psforever.services.avatar
|
||||||
import net.psforever.objects.Player
|
import net.psforever.objects.Player
|
||||||
import net.psforever.objects.avatar.scoring.KDAStat
|
import net.psforever.objects.avatar.scoring.KDAStat
|
||||||
import net.psforever.objects.ballistics.Projectile
|
import net.psforever.objects.ballistics.Projectile
|
||||||
import net.psforever.objects.ce.Deployable
|
|
||||||
import net.psforever.objects.equipment.Equipment
|
import net.psforever.objects.equipment.Equipment
|
||||||
import net.psforever.objects.inventory.InventoryItem
|
import net.psforever.objects.inventory.InventoryItem
|
||||||
import net.psforever.objects.serverobject.environment.interaction.common.Watery.OxygenStateTarget
|
import net.psforever.objects.serverobject.environment.interaction.common.Watery.OxygenStateTarget
|
||||||
|
|
@ -44,7 +43,6 @@ object AvatarAction {
|
||||||
final case class ConcealPlayer(player_guid: PlanetSideGUID) extends Action
|
final case class ConcealPlayer(player_guid: PlanetSideGUID) extends Action
|
||||||
final case class EnvironmentalDamage(player_guid: PlanetSideGUID, source_guid: PlanetSideGUID, amount: Int)
|
final case class EnvironmentalDamage(player_guid: PlanetSideGUID, source_guid: PlanetSideGUID, amount: Int)
|
||||||
extends Action
|
extends Action
|
||||||
final case class DeployItem(player_guid: PlanetSideGUID, item: Deployable) extends Action
|
|
||||||
final case class DeactivateImplantSlot(player_guid: PlanetSideGUID, slot: Int) extends Action
|
final case class DeactivateImplantSlot(player_guid: PlanetSideGUID, slot: Int) extends Action
|
||||||
final case class ActivateImplantSlot(player_guid: PlanetSideGUID, slot: Int) extends Action
|
final case class ActivateImplantSlot(player_guid: PlanetSideGUID, slot: Int) extends Action
|
||||||
final case class Destroy(victim: PlanetSideGUID, killer: PlanetSideGUID, weapon: PlanetSideGUID, pos: Vector3)
|
final case class Destroy(victim: PlanetSideGUID, killer: PlanetSideGUID, weapon: PlanetSideGUID, pos: Vector3)
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ package net.psforever.services.local
|
||||||
import akka.actor.{Actor, Props}
|
import akka.actor.{Actor, Props}
|
||||||
import net.psforever.objects.serverobject.terminals.Terminal
|
import net.psforever.objects.serverobject.terminals.Terminal
|
||||||
import net.psforever.objects.zones.Zone
|
import net.psforever.objects.zones.Zone
|
||||||
import net.psforever.packet.game.{TriggeredEffect, TriggeredEffectLocation}
|
import net.psforever.packet.game.{ObjectCreateMessage, TriggeredEffect, TriggeredEffectLocation}
|
||||||
import net.psforever.services.local.support.CaptureFlagManager
|
import net.psforever.services.local.support.CaptureFlagManager
|
||||||
import net.psforever.types.PlanetSideGUID
|
import net.psforever.types.PlanetSideGUID
|
||||||
import net.psforever.services.local.support._
|
import net.psforever.services.local.support._
|
||||||
|
|
@ -45,6 +45,16 @@ class LocalService(zone: Zone) extends Actor {
|
||||||
|
|
||||||
case LocalServiceMessage(forChannel, action) =>
|
case LocalServiceMessage(forChannel, action) =>
|
||||||
action match {
|
action match {
|
||||||
|
case LocalAction.DeployItem(item) =>
|
||||||
|
val definition = item.Definition
|
||||||
|
val objectData = definition.Packet.ConstructorData(item).get
|
||||||
|
LocalEvents.publish(
|
||||||
|
LocalServiceResponse(
|
||||||
|
s"/$forChannel/Local",
|
||||||
|
Service.defaultPlayerGUID,
|
||||||
|
LocalResponse.SendResponse(ObjectCreateMessage(definition.ObjectId, item.GUID, objectData))
|
||||||
|
)
|
||||||
|
)
|
||||||
case LocalAction.DeployableMapIcon(player_guid, behavior, deployInfo) =>
|
case LocalAction.DeployableMapIcon(player_guid, behavior, deployInfo) =>
|
||||||
LocalEvents.publish(
|
LocalEvents.publish(
|
||||||
LocalServiceResponse(
|
LocalServiceResponse(
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ object LocalServiceMessage {
|
||||||
object LocalAction {
|
object LocalAction {
|
||||||
trait Action
|
trait Action
|
||||||
|
|
||||||
|
final case class DeployItem(item: Deployable) extends Action
|
||||||
final case class DeployableMapIcon(
|
final case class DeployableMapIcon(
|
||||||
player_guid: PlanetSideGUID,
|
player_guid: PlanetSideGUID,
|
||||||
behavior: DeploymentAction.Value,
|
behavior: DeploymentAction.Value,
|
||||||
|
|
|
||||||
30
src/test/scala/game/GenericObjectAction2MessageTest.scala
Normal file
30
src/test/scala/game/GenericObjectAction2MessageTest.scala
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
// Copyright (c) 2017 PSForever
|
||||||
|
package game
|
||||||
|
|
||||||
|
import org.specs2.mutable._
|
||||||
|
import net.psforever.packet._
|
||||||
|
import net.psforever.packet.game._
|
||||||
|
import net.psforever.types.PlanetSideGUID
|
||||||
|
import scodec.bits._
|
||||||
|
|
||||||
|
class GenericObjectAction2MessageTest extends Specification {
|
||||||
|
val string = hex"80 38C139212 0"
|
||||||
|
|
||||||
|
"decode" in {
|
||||||
|
PacketCoding.decodePacket(string).require match {
|
||||||
|
case GenericObjectAction2Message(unk, guid1, guid2) =>
|
||||||
|
unk mustEqual 1
|
||||||
|
guid1 mustEqual PlanetSideGUID(2502)
|
||||||
|
guid2 mustEqual PlanetSideGUID(2505)
|
||||||
|
case _ =>
|
||||||
|
ko
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
"encode" in {
|
||||||
|
val msg = GenericObjectAction2Message(1, PlanetSideGUID(2502), PlanetSideGUID(2505))
|
||||||
|
val pkt = PacketCoding.encodePacket(msg).require.toByteVector
|
||||||
|
|
||||||
|
pkt mustEqual string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -32,9 +32,9 @@ class SmallTurretDataTest extends Specification {
|
||||||
deploy.v1 mustEqual true
|
deploy.v1 mustEqual true
|
||||||
deploy.v2.isEmpty mustEqual true
|
deploy.v2.isEmpty mustEqual true
|
||||||
deploy.jammered mustEqual false
|
deploy.jammered mustEqual false
|
||||||
deploy.v4.contains(false) mustEqual true
|
deploy.v4.isEmpty mustEqual true
|
||||||
deploy.v5.isEmpty mustEqual true
|
deploy.v5.isEmpty mustEqual true
|
||||||
deploy.guid mustEqual PlanetSideGUID(7742)
|
deploy.guid mustEqual PlanetSideGUID(3871)
|
||||||
|
|
||||||
health mustEqual 0
|
health mustEqual 0
|
||||||
case _ =>
|
case _ =>
|
||||||
|
|
@ -63,9 +63,9 @@ class SmallTurretDataTest extends Specification {
|
||||||
deploy.v1 mustEqual true
|
deploy.v1 mustEqual true
|
||||||
deploy.v2.isEmpty mustEqual true
|
deploy.v2.isEmpty mustEqual true
|
||||||
deploy.jammered mustEqual false
|
deploy.jammered mustEqual false
|
||||||
deploy.v4.contains(true) mustEqual true
|
deploy.v4.isEmpty mustEqual true
|
||||||
deploy.v5.isEmpty mustEqual true
|
deploy.v5.isEmpty mustEqual true
|
||||||
deploy.guid mustEqual PlanetSideGUID(8208)
|
deploy.guid mustEqual PlanetSideGUID(4232)
|
||||||
|
|
||||||
health mustEqual 255
|
health mustEqual 255
|
||||||
|
|
||||||
|
|
@ -124,7 +124,7 @@ class SmallTurretDataTest extends Specification {
|
||||||
val obj = SmallTurretData(
|
val obj = SmallTurretData(
|
||||||
CommonFieldDataWithPlacement(
|
CommonFieldDataWithPlacement(
|
||||||
PlacementData(Vector3(4577.7812f, 5624.828f, 72.046875f), Vector3(0, 2.8125f, 264.375f)),
|
PlacementData(Vector3(4577.7812f, 5624.828f, 72.046875f), Vector3(0, 2.8125f, 264.375f)),
|
||||||
CommonFieldData(PlanetSideEmpire.NC, false, true, true, None, false, Some(false), None, PlanetSideGUID(7742))
|
CommonFieldData(PlanetSideEmpire.NC, bops = false, alternate = true, v1 = true, None, jammered = false, None, None, PlanetSideGUID(3871))
|
||||||
),
|
),
|
||||||
0
|
0
|
||||||
)
|
)
|
||||||
|
|
@ -137,7 +137,7 @@ class SmallTurretDataTest extends Specification {
|
||||||
val obj = SmallTurretData(
|
val obj = SmallTurretData(
|
||||||
CommonFieldDataWithPlacement(
|
CommonFieldDataWithPlacement(
|
||||||
PlacementData(Vector3(4527.633f, 6271.3594f, 70.265625f), Vector3(0, 0, 154.6875f)),
|
PlacementData(Vector3(4527.633f, 6271.3594f, 70.265625f), Vector3(0, 0, 154.6875f)),
|
||||||
CommonFieldData(PlanetSideEmpire.VS, false, false, true, None, false, Some(true), None, PlanetSideGUID(8208))
|
CommonFieldData(PlanetSideEmpire.VS, bops = false, alternate = false, v1 = true, None, jammered = false, None, None, PlanetSideGUID(4232))
|
||||||
),
|
),
|
||||||
255,
|
255,
|
||||||
InventoryData(
|
InventoryData(
|
||||||
|
|
@ -149,11 +149,11 @@ class SmallTurretDataTest extends Specification {
|
||||||
WeaponData(
|
WeaponData(
|
||||||
CommonFieldData(
|
CommonFieldData(
|
||||||
PlanetSideEmpire.NEUTRAL,
|
PlanetSideEmpire.NEUTRAL,
|
||||||
false,
|
bops = false,
|
||||||
false,
|
alternate = false,
|
||||||
true,
|
v1 = true,
|
||||||
None,
|
None,
|
||||||
false,
|
jammered = false,
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
PlanetSideGUID(0)
|
PlanetSideGUID(0)
|
||||||
|
|
@ -166,11 +166,11 @@ class SmallTurretDataTest extends Specification {
|
||||||
0,
|
0,
|
||||||
CommonFieldData(
|
CommonFieldData(
|
||||||
PlanetSideEmpire.NEUTRAL,
|
PlanetSideEmpire.NEUTRAL,
|
||||||
false,
|
bops = false,
|
||||||
false,
|
alternate = false,
|
||||||
true,
|
v1 = true,
|
||||||
None,
|
None,
|
||||||
false,
|
jammered = false,
|
||||||
Some(false),
|
Some(false),
|
||||||
None,
|
None,
|
||||||
PlanetSideGUID(0)
|
PlanetSideGUID(0)
|
||||||
|
|
|
||||||
|
|
@ -29,9 +29,9 @@ class TRAPDataTest extends Specification {
|
||||||
deploy.v1 mustEqual true
|
deploy.v1 mustEqual true
|
||||||
deploy.v2.isEmpty mustEqual true
|
deploy.v2.isEmpty mustEqual true
|
||||||
deploy.jammered mustEqual false
|
deploy.jammered mustEqual false
|
||||||
deploy.v4.contains(true) mustEqual true
|
deploy.v4.isEmpty mustEqual true
|
||||||
deploy.v5.isEmpty mustEqual true
|
deploy.v5.isEmpty mustEqual true
|
||||||
deploy.guid mustEqual PlanetSideGUID(4748)
|
deploy.guid mustEqual PlanetSideGUID(2502)
|
||||||
health mustEqual 255
|
health mustEqual 255
|
||||||
case _ =>
|
case _ =>
|
||||||
ko
|
ko
|
||||||
|
|
@ -45,7 +45,7 @@ class TRAPDataTest extends Specification {
|
||||||
val obj = TRAPData(
|
val obj = TRAPData(
|
||||||
CommonFieldDataWithPlacement(
|
CommonFieldDataWithPlacement(
|
||||||
PlacementData(Vector3(3572.4453f, 3277.9766f, 114.0f), Vector3.z(90)),
|
PlacementData(Vector3(3572.4453f, 3277.9766f, 114.0f), Vector3.z(90)),
|
||||||
CommonFieldData(PlanetSideEmpire.VS, false, false, true, None, false, Some(true), None, PlanetSideGUID(4748))
|
CommonFieldData(PlanetSideEmpire.VS, bops = false, alternate = false, v1 = true, None, jammered = false, None, None, PlanetSideGUID(2502))
|
||||||
),
|
),
|
||||||
255
|
255
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,7 @@ class DeployableBehaviorSetupTest extends ActorTest {
|
||||||
case _ => assert(false, "self-setup test - no spawn fx")
|
case _ => assert(false, "self-setup test - no spawn fx")
|
||||||
}
|
}
|
||||||
eventsMsgs(1) match {
|
eventsMsgs(1) match {
|
||||||
case AvatarServiceMessage("test", AvatarAction.DeployItem(PlanetSideGUID(0), obj)) =>
|
case LocalServiceMessage("test", LocalAction.DeployItem(obj)) =>
|
||||||
assert(obj eq jmine, "self-setup test - not same mine")
|
assert(obj eq jmine, "self-setup test - not same mine")
|
||||||
case _ =>
|
case _ =>
|
||||||
assert( false, "self-setup test - wrong deploy message")
|
assert( false, "self-setup test - wrong deploy message")
|
||||||
|
|
@ -189,7 +189,7 @@ class DeployableBehaviorSetupOwnedP2Test extends FreedContextActorTest {
|
||||||
case _ => assert(false, "owned setup test, 2 - no spawn fx")
|
case _ => assert(false, "owned setup test, 2 - no spawn fx")
|
||||||
}
|
}
|
||||||
eventsMsgs(3) match {
|
eventsMsgs(3) match {
|
||||||
case AvatarServiceMessage("test", AvatarAction.DeployItem(PlanetSideGUID(0), obj)) =>
|
case LocalServiceMessage("test", LocalAction.DeployItem(obj)) =>
|
||||||
assert(obj eq jmine, "owned setup test, 2 - not same mine")
|
assert(obj eq jmine, "owned setup test, 2 - not same mine")
|
||||||
case _ =>
|
case _ =>
|
||||||
assert( false, "owned setup test, 2 - wrong deploy message")
|
assert( false, "owned setup test, 2 - wrong deploy message")
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,7 @@ class TelepadDeployableNoRouterTest extends ActorTest {
|
||||||
|
|
||||||
val eventsMsgs = eventsProbe.receiveN(4, 10.seconds)
|
val eventsMsgs = eventsProbe.receiveN(4, 10.seconds)
|
||||||
eventsMsgs.head match {
|
eventsMsgs.head match {
|
||||||
case AvatarServiceMessage("test", AvatarAction.DeployItem(PlanetSideGUID(0), obj)) =>
|
case LocalServiceMessage("test", LocalAction.DeployItem(obj)) =>
|
||||||
assert(obj eq telepad, "no-router telepad deployable testt - not same telepad")
|
assert(obj eq telepad, "no-router telepad deployable testt - not same telepad")
|
||||||
case _ =>
|
case _ =>
|
||||||
assert( false, "no-router telepad deployable test - wrong deploy message")
|
assert( false, "no-router telepad deployable test - wrong deploy message")
|
||||||
|
|
@ -117,7 +117,7 @@ class TelepadDeployableNoActivationTest extends ActorTest {
|
||||||
|
|
||||||
val eventsMsgs = eventsProbe.receiveN(4, 10.seconds)
|
val eventsMsgs = eventsProbe.receiveN(4, 10.seconds)
|
||||||
eventsMsgs.head match {
|
eventsMsgs.head match {
|
||||||
case AvatarServiceMessage("test", AvatarAction.DeployItem(PlanetSideGUID(0), obj)) =>
|
case LocalServiceMessage("test", LocalAction.DeployItem(obj)) =>
|
||||||
assert(obj eq telepad, "no-activate telepad deployable testt - not same telepad")
|
assert(obj eq telepad, "no-activate telepad deployable testt - not same telepad")
|
||||||
case _ =>
|
case _ =>
|
||||||
assert( false, "no-activate telepad deployable test - wrong deploy message")
|
assert( false, "no-activate telepad deployable test - wrong deploy message")
|
||||||
|
|
@ -190,7 +190,7 @@ class TelepadDeployableAttemptTest extends ActorTest {
|
||||||
val eventsMsgs = eventsProbe.receiveN(2, 10.seconds)
|
val eventsMsgs = eventsProbe.receiveN(2, 10.seconds)
|
||||||
val routerMsgs = routerProbe.receiveN(1, 10.seconds)
|
val routerMsgs = routerProbe.receiveN(1, 10.seconds)
|
||||||
eventsMsgs.head match {
|
eventsMsgs.head match {
|
||||||
case AvatarServiceMessage("test", AvatarAction.DeployItem(PlanetSideGUID(0), obj)) =>
|
case LocalServiceMessage("test", LocalAction.DeployItem(obj)) =>
|
||||||
assert(obj eq telepad, "link attempt telepad deployable testt - not same telepad")
|
assert(obj eq telepad, "link attempt telepad deployable testt - not same telepad")
|
||||||
case _ =>
|
case _ =>
|
||||||
assert( false, "link attempt telepad deployable test - wrong deploy message")
|
assert( false, "link attempt telepad deployable test - wrong deploy message")
|
||||||
|
|
@ -263,7 +263,7 @@ class TelepadDeployableResponseFromRouterTest extends FreedContextActorTest {
|
||||||
|
|
||||||
val eventsMsgs = eventsProbe.receiveN(9, 10.seconds)
|
val eventsMsgs = eventsProbe.receiveN(9, 10.seconds)
|
||||||
eventsMsgs.head match {
|
eventsMsgs.head match {
|
||||||
case AvatarServiceMessage("test", AvatarAction.DeployItem(PlanetSideGUID(0), obj)) =>
|
case LocalServiceMessage("test", LocalAction.DeployItem(obj)) =>
|
||||||
assert(obj eq telepad, "link to router test - not same telepad")
|
assert(obj eq telepad, "link to router test - not same telepad")
|
||||||
case _ =>
|
case _ =>
|
||||||
assert( false, "link to router test - wrong deploy message")
|
assert( false, "link to router test - wrong deploy message")
|
||||||
|
|
|
||||||
|
|
@ -78,6 +78,31 @@ class LocalService5Test extends ActorTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class DeployItemTest extends ActorTest {
|
||||||
|
ServiceManager.boot(system)
|
||||||
|
val service = system.actorOf(Props(classOf[LocalService], Zone.Nowhere), "deploy-item-test-service")
|
||||||
|
val objDef = GlobalDefinitions.motionalarmsensor
|
||||||
|
val obj = new SensorDeployable(objDef)
|
||||||
|
obj.Position = Vector3(1, 2, 3)
|
||||||
|
obj.Orientation = Vector3(4, 5, 6)
|
||||||
|
obj.GUID = PlanetSideGUID(40)
|
||||||
|
val pkt = ObjectCreateMessage(
|
||||||
|
objDef.ObjectId,
|
||||||
|
obj.GUID,
|
||||||
|
objDef.Packet.ConstructorData(obj).get
|
||||||
|
)
|
||||||
|
|
||||||
|
"AvatarService" should {
|
||||||
|
"pass DeployItem" in {
|
||||||
|
service ! Service.Join("test")
|
||||||
|
service ! LocalServiceMessage("test", LocalAction.DeployItem(obj))
|
||||||
|
expectMsg(LocalServiceResponse("/test/Local", PlanetSideGUID(0), LocalResponse.SendResponse(pkt)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class DeployableMapIconTest extends ActorTest {
|
class DeployableMapIconTest extends ActorTest {
|
||||||
ServiceManager.boot(system)
|
ServiceManager.boot(system)
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue