mirror of
https://github.com/2revoemag/PSF-BotServer.git
synced 2026-01-20 02:24:45 +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
|
|
@ -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 {
|
||||
ServiceManager.boot(system)
|
||||
val service = system.actorOf(Props(classOf[AvatarService], Zone.Nowhere), "release-test-service")
|
||||
|
|
|
|||
|
|
@ -563,7 +563,7 @@ class GeneralOperations(
|
|||
* @param unk2 na
|
||||
*/
|
||||
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 net.psforever.actors.session.spectator.SpectatorMode
|
||||
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.definition.converter.OCM
|
||||
import net.psforever.objects.inventory.InventoryItem
|
||||
import net.psforever.objects.serverobject.interior.Sidedness
|
||||
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.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.ce.{Deployable, DeployableCategory, DeployedItem, TelepadLike}
|
||||
import net.psforever.objects.definition.SpecialExoSuitDefinition
|
||||
|
|
@ -215,104 +216,13 @@ class ZoningOperations(
|
|||
sendResponse(ReplicationStreamMessage(5, Some(6), Vector.empty)) //clear squad list
|
||||
sendResponse(PlanetsideAttributeMessage(PlanetSideGUID(0), 112, 0)) // disable festive backpacks
|
||||
|
||||
//find and reclaim own deployables, if any
|
||||
val foundDeployables = continent.DeployableList.filter {
|
||||
case _: BoomerDeployable => false //if we do find boomers for any reason, ignore them
|
||||
case dobj => dobj.OwnerName.contains(player.Name) && dobj.Health > 0
|
||||
}
|
||||
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
|
||||
val deployables = continent.DeployableList
|
||||
reclaimOurDeployables(deployables, name, manageDeployablesWith(player.GUID, avatar.deployables))
|
||||
drawDeployableIconsOnMap(
|
||||
depictDeployables(deployables).filter(_.Faction == faction)
|
||||
)
|
||||
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
|
||||
continent.EquipmentOnGround.foreach(item => {
|
||||
continent.EquipmentOnGround.foreach { item =>
|
||||
val definition = item.Definition
|
||||
sendResponse(
|
||||
ObjectCreateMessage(
|
||||
|
|
@ -324,26 +234,19 @@ class ZoningOperations(
|
|||
)
|
||||
)
|
||||
)
|
||||
})
|
||||
}
|
||||
//load active players in zone (excepting players who are seated or players who are us)
|
||||
val live = continent.LivePlayers
|
||||
live
|
||||
.filterNot(tplayer => {
|
||||
.filterNot { tplayer =>
|
||||
tplayer.GUID == player.GUID || tplayer.VehicleSeated.nonEmpty
|
||||
})
|
||||
.foreach(targetPlayer => {
|
||||
val targetDefinition = player.avatar.definition
|
||||
sendResponse(
|
||||
ObjectCreateMessage(
|
||||
targetDefinition.ObjectId,
|
||||
targetPlayer.GUID,
|
||||
targetDefinition.Packet.ConstructorData(targetPlayer).get
|
||||
)
|
||||
)
|
||||
}
|
||||
.foreach { targetPlayer =>
|
||||
sendResponse(OCM.apply(targetPlayer))
|
||||
if (targetPlayer.UsingSpecial == SpecialExoSuitDefinition.Mode.Anchored) {
|
||||
sendResponse(PlanetsideAttributeMessage(targetPlayer.GUID, 19, 1))
|
||||
}
|
||||
})
|
||||
}
|
||||
//load corpses in zone
|
||||
continent.Corpses.foreach {
|
||||
spawn.DepictPlayerAsCorpse
|
||||
|
|
@ -376,10 +279,7 @@ class ZoningOperations(
|
|||
//active vehicles (and some wreckage)
|
||||
vehicles.foreach { vehicle =>
|
||||
val vguid = vehicle.GUID
|
||||
val vdefinition = vehicle.Definition
|
||||
sendResponse(
|
||||
ObjectCreateMessage(vdefinition.ObjectId, vguid, vdefinition.Packet.ConstructorData(vehicle).get)
|
||||
)
|
||||
sendResponse(OCM.apply(vehicle))
|
||||
//occupants other than driver (with exceptions)
|
||||
vehicle.Seats
|
||||
.filter {
|
||||
|
|
@ -393,15 +293,10 @@ class ZoningOperations(
|
|||
}
|
||||
.foreach {
|
||||
case (index, seat) =>
|
||||
val targetPlayer = seat.occupant.get
|
||||
val targetDefiniton = targetPlayer.avatar.definition
|
||||
sendResponse(
|
||||
ObjectCreateMessage(
|
||||
targetDefiniton.ObjectId,
|
||||
targetPlayer.GUID,
|
||||
ObjectCreateMessageParent(vguid, index),
|
||||
targetDefiniton.Packet.ConstructorData(targetPlayer).get
|
||||
)
|
||||
OCM.apply(seat.occupant.get)
|
||||
.asInstanceOf[ObjectCreateMessage]
|
||||
.copy(parentInfo = Some(ObjectCreateMessageParent(vguid, index)))
|
||||
)
|
||||
}
|
||||
vehicle.SubsystemMessages().foreach { sendResponse }
|
||||
|
|
@ -411,8 +306,8 @@ class ZoningOperations(
|
|||
Vehicles.ReloadAccessPermissions(vehicle, player.Name)
|
||||
}
|
||||
//our vehicle would have already been loaded; see NewPlayerLoaded/AvatarCreate
|
||||
usedVehicle.headOption match {
|
||||
case Some(vehicle) =>
|
||||
usedVehicle.headOption.collect {
|
||||
case vehicle =>
|
||||
//subsystems
|
||||
vehicle.Actor ! Vehicle.UpdateSubsystemStates(player.Name, Some(false))
|
||||
//depict any other passengers already in this zone
|
||||
|
|
@ -430,15 +325,10 @@ class ZoningOperations(
|
|||
}
|
||||
.foreach {
|
||||
case (index, seat) =>
|
||||
val targetPlayer = seat.occupant.get
|
||||
val targetDefinition = targetPlayer.avatar.definition
|
||||
sendResponse(
|
||||
ObjectCreateMessage(
|
||||
targetDefinition.ObjectId,
|
||||
targetPlayer.GUID,
|
||||
ObjectCreateMessageParent(vguid, index),
|
||||
targetDefinition.Packet.ConstructorData(targetPlayer).get
|
||||
)
|
||||
OCM.apply(seat.occupant.get)
|
||||
.asInstanceOf[ObjectCreateMessage]
|
||||
.copy(parentInfo = Some(ObjectCreateMessageParent(vguid, index)))
|
||||
)
|
||||
}
|
||||
//since we would have only subscribed recently, we need to reload mount access states
|
||||
|
|
@ -449,10 +339,9 @@ class ZoningOperations(
|
|||
if (vehicle.Shields > 0) {
|
||||
sendResponse(PlanetsideAttributeMessage(vguid, vehicle.Definition.shieldUiAttribute, vehicle.Shields))
|
||||
}
|
||||
case _ => () //no vehicle
|
||||
}
|
||||
//vehicle wreckages
|
||||
wreckages.foreach(vehicle => {
|
||||
wreckages.foreach { vehicle =>
|
||||
sendResponse(
|
||||
ObjectCreateMessage(
|
||||
vehicle.Definition.DestroyedModel.get.id,
|
||||
|
|
@ -460,17 +349,14 @@ class ZoningOperations(
|
|||
DestroyedVehicleConverter.converter.ConstructorData(vehicle).get
|
||||
)
|
||||
)
|
||||
})
|
||||
}
|
||||
//cargo occupants (including our own vehicle as cargo)
|
||||
allActiveVehicles.collect {
|
||||
case vehicle if vehicle.CargoHolds.nonEmpty =>
|
||||
vehicle.CargoHolds.collect {
|
||||
case (_index, hold: Cargo) if hold.isOccupied =>
|
||||
CarrierBehavior.CargoMountBehaviorForAll(
|
||||
vehicle,
|
||||
hold.occupant.get,
|
||||
_index
|
||||
) //CargoMountBehaviorForUs can fail to attach the cargo vehicle on some clients
|
||||
//CargoMountBehaviorForUs can fail to attach the cargo vehicle on some clients
|
||||
CarrierBehavior.CargoMountBehaviorForAll(vehicle, hold.occupant.get, _index)
|
||||
}
|
||||
}
|
||||
//special deploy states
|
||||
|
|
@ -492,8 +378,8 @@ class ZoningOperations(
|
|||
}
|
||||
deployedVehicles.filter(_.Definition == GlobalDefinitions.router).foreach { obj =>
|
||||
//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.Deployed, 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))
|
||||
sessionLogic.general.toggleTeleportSystem(obj, TelepadLike.AppraiseTeleportationSystem(obj, continent))
|
||||
}
|
||||
ServiceManager.serviceManager
|
||||
|
|
@ -504,41 +390,30 @@ class ZoningOperations(
|
|||
case _ =>
|
||||
}
|
||||
//implant terminals
|
||||
continent.map.terminalToInterface.foreach({
|
||||
continent.map.terminalToInterface.foreach {
|
||||
case (terminal_guid, interface_guid) =>
|
||||
val parent_guid = PlanetSideGUID(terminal_guid)
|
||||
continent.GUID(interface_guid) match {
|
||||
case Some(obj: Terminal) =>
|
||||
val objDef = obj.Definition
|
||||
continent.GUID(interface_guid).collect {
|
||||
case obj: Terminal =>
|
||||
sendResponse(
|
||||
ObjectCreateMessage(
|
||||
objDef.ObjectId,
|
||||
PlanetSideGUID(interface_guid),
|
||||
ObjectCreateMessageParent(parent_guid, 1),
|
||||
objDef.Packet.ConstructorData(obj).get
|
||||
)
|
||||
OCM.apply(obj)
|
||||
.asInstanceOf[ObjectCreateMessage]
|
||||
.copy(parentInfo = Some(ObjectCreateMessageParent(parent_guid, 1)))
|
||||
)
|
||||
case _ => ()
|
||||
}
|
||||
//mount terminal occupants
|
||||
continent.GUID(terminal_guid) match {
|
||||
case Some(obj: Mountable) =>
|
||||
obj.Seats(0).occupant match {
|
||||
case Some(targetPlayer: Player) =>
|
||||
val targetDefinition = targetPlayer.avatar.definition
|
||||
continent.GUID(terminal_guid).collect {
|
||||
case obj: Mountable =>
|
||||
obj.Seats(0).occupant.collect {
|
||||
case occupant: Player =>
|
||||
sendResponse(
|
||||
ObjectCreateMessage(
|
||||
targetDefinition.ObjectId,
|
||||
targetPlayer.GUID,
|
||||
ObjectCreateMessageParent(parent_guid, 0),
|
||||
targetDefinition.Packet.ConstructorData(targetPlayer).get
|
||||
)
|
||||
OCM.apply(occupant)
|
||||
.asInstanceOf[ObjectCreateMessage]
|
||||
.copy(parentInfo = Some(ObjectCreateMessageParent(parent_guid, 0)))
|
||||
)
|
||||
case _ => ()
|
||||
}
|
||||
case _ => ()
|
||||
}
|
||||
})
|
||||
}
|
||||
//facility turrets
|
||||
continent.map.turretToWeapon
|
||||
.map { case (turret_guid: Int, _) => continent.GUID(turret_guid) }
|
||||
|
|
@ -549,14 +424,10 @@ class ZoningOperations(
|
|||
if (!turret.isUpgrading) {
|
||||
turret.ControlledWeapon(wepNumber = 1).foreach {
|
||||
case obj: Tool =>
|
||||
val objDef = obj.Definition
|
||||
sendResponse(
|
||||
ObjectCreateMessage(
|
||||
objDef.ObjectId,
|
||||
obj.GUID,
|
||||
ObjectCreateMessageParent(pguid, 1),
|
||||
objDef.Packet.ConstructorData(obj).get
|
||||
)
|
||||
OCM.apply(obj)
|
||||
.asInstanceOf[ObjectCreateMessage]
|
||||
.copy(parentInfo = Some(ObjectCreateMessageParent(pguid, 1)))
|
||||
)
|
||||
case _ => ()
|
||||
}
|
||||
|
|
@ -564,38 +435,19 @@ class ZoningOperations(
|
|||
//reserved ammunition?
|
||||
//TODO need to register if it exists
|
||||
//mount turret occupant
|
||||
turret.Seats(0).occupant match {
|
||||
case Some(targetPlayer: Player) =>
|
||||
val targetDefinition = targetPlayer.avatar.definition
|
||||
turret.Seats(0).occupant.collect {
|
||||
case occupant: Player =>
|
||||
sendResponse(
|
||||
ObjectCreateMessage(
|
||||
targetDefinition.ObjectId,
|
||||
targetPlayer.GUID,
|
||||
ObjectCreateMessageParent(pguid, 0),
|
||||
targetDefinition.Packet.ConstructorData(targetPlayer).get
|
||||
)
|
||||
OCM.apply(occupant)
|
||||
.asInstanceOf[ObjectCreateMessage]
|
||||
.copy(parentInfo = Some(ObjectCreateMessageParent(pguid, 0)))
|
||||
)
|
||||
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
|
||||
continent.Projectiles.foreach { projectile =>
|
||||
val definition = projectile.Definition
|
||||
sendResponse(
|
||||
ObjectCreateMessage(
|
||||
definition.ObjectId,
|
||||
projectile.GUID,
|
||||
definition.Packet.ConstructorData(projectile).get
|
||||
)
|
||||
)
|
||||
sendResponse(OCM.apply(projectile))
|
||||
}
|
||||
//spawn point update request
|
||||
continent.VehicleEvents ! VehicleServiceMessage(
|
||||
|
|
@ -1166,14 +1018,7 @@ class ZoningOperations(
|
|||
// sync capture flags
|
||||
case llu: CaptureFlag =>
|
||||
// Create LLU
|
||||
sendResponse(
|
||||
ObjectCreateMessage(
|
||||
llu.Definition.ObjectId,
|
||||
llu.GUID,
|
||||
llu.Definition.Packet.ConstructorData(llu).get
|
||||
)
|
||||
)
|
||||
|
||||
sendResponse(OCM.apply(llu))
|
||||
// Attach it to a player if it has a carrier
|
||||
if (llu.Carrier.nonEmpty) {
|
||||
continent.LocalEvents ! LocalServiceMessage(
|
||||
|
|
@ -1755,6 +1600,188 @@ class ZoningOperations(
|
|||
*/
|
||||
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 */
|
||||
|
||||
class SpawnOperations() {
|
||||
|
|
@ -2298,10 +2325,11 @@ class ZoningOperations(
|
|||
//vehicle and driver/passenger
|
||||
interstellarFerry = None
|
||||
val vdef = vehicle.Definition
|
||||
val vObjectId = vdef.ObjectId
|
||||
val vguid = vehicle.GUID
|
||||
vehicle.Position = shiftPosition.getOrElse(vehicle.Position)
|
||||
vehicle.Orientation = shiftOrientation.getOrElse(vehicle.Orientation)
|
||||
val vdata = if (seat == 0) {
|
||||
if (seat == 0) {
|
||||
//driver
|
||||
if (vehicle.Zone ne continent) {
|
||||
continent.Transport ! Zone.Vehicle.Spawn(vehicle)
|
||||
|
|
@ -2311,7 +2339,7 @@ class ZoningOperations(
|
|||
mount.unmount(player)
|
||||
player.VehicleSeated = None
|
||||
val data = vdef.Packet.ConstructorData(vehicle).get
|
||||
sendResponse(ObjectCreateMessage(vehicle.Definition.ObjectId, vguid, data))
|
||||
sendResponse(ObjectCreateMessage(vObjectId, vguid, data))
|
||||
mount.mount(player)
|
||||
player.VehicleSeated = vguid
|
||||
Vehicles.Own(vehicle, player)
|
||||
|
|
@ -2320,7 +2348,7 @@ class ZoningOperations(
|
|||
.foreach { _.MountedIn = vguid }
|
||||
events ! VehicleServiceMessage(
|
||||
zoneid,
|
||||
VehicleAction.LoadVehicle(player.GUID, vehicle, vdef.ObjectId, vguid, data)
|
||||
VehicleAction.LoadVehicle(player.GUID, vehicle, vObjectId, vguid, data)
|
||||
)
|
||||
carrierInfo match {
|
||||
case (Some(carrier), Some((index, _))) =>
|
||||
|
|
@ -2329,18 +2357,15 @@ class ZoningOperations(
|
|||
vehicle.MountedIn = None
|
||||
}
|
||||
vehicle.allowInteraction = true
|
||||
data
|
||||
} else {
|
||||
//passenger
|
||||
//non-drivers are not rendered in the vehicle at this time
|
||||
val data = vdef.Packet.ConstructorData(vehicle).get
|
||||
sendResponse(ObjectCreateMessage(vehicle.Definition.ObjectId, vguid, data))
|
||||
sendResponse(OCM.apply(vehicle))
|
||||
carrierInfo match {
|
||||
case (Some(carrier), Some((index, _))) =>
|
||||
CargoMountBehaviorForUs(carrier, vehicle, index)
|
||||
case _ => ()
|
||||
}
|
||||
data
|
||||
}
|
||||
val originalSeated = player.VehicleSeated
|
||||
player.VehicleSeated = vguid
|
||||
|
|
@ -2357,25 +2382,26 @@ class ZoningOperations(
|
|||
)
|
||||
}
|
||||
Vehicles.ReloadAccessPermissions(vehicle, player.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")
|
||||
log.debug(s"AvatarCreate (vehicle): ${player.Name}'s ${vdef.Name}")
|
||||
AvatarCreateInVehicle(player, vehicle, seat)
|
||||
|
||||
case _ =>
|
||||
player.VehicleSeated = None
|
||||
val packet = player.avatar.definition.Packet
|
||||
val data = packet.DetailedConstructorData(player).get
|
||||
val guid = player.GUID
|
||||
sendResponse(ObjectCreateDetailedMessage(ObjectClass.avatar, guid, data))
|
||||
val definition = player.avatar.definition
|
||||
val guid = player.GUID
|
||||
sendResponse(OCM.detailed(player))
|
||||
continent.AvatarEvents ! AvatarServiceMessage(
|
||||
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)
|
||||
avatarActor ! AvatarActor.RefreshPurchaseTimes()
|
||||
drawDeployableIconsOnMap(
|
||||
depictDeployablesUponRevival(
|
||||
reclaimOurDeployables(continent.DeployableList, player.Name, reassignDeployablesTo(player.GUID))
|
||||
)
|
||||
)
|
||||
//begin looking for conditions to set the avatar
|
||||
context.system.scheduler.scheduleOnce(delay = 250 millisecond, context.self, SessionActor.SetCurrentAvatar(player, 200))
|
||||
}
|
||||
|
|
@ -2403,11 +2429,9 @@ class ZoningOperations(
|
|||
val pguid = tplayer.GUID
|
||||
val vguid = vehicle.GUID
|
||||
tplayer.VehicleSeated = None
|
||||
val pdata = pdef.Packet.DetailedConstructorData(tplayer).get
|
||||
tplayer.VehicleSeated = vguid
|
||||
log.debug(s"AvatarCreateInVehicle: ${player.Name}")
|
||||
log.trace(s"AvatarCreateInVehicle: ${player.Name} - $pguid -> $pdata")
|
||||
sendResponse(ObjectCreateDetailedMessage(pdef.ObjectId, pguid, pdata))
|
||||
sendResponse(OCM.detailed(tplayer))
|
||||
if (seat == 0 || vehicle.WeaponControlledFromSeat(seat).nonEmpty) {
|
||||
sendResponse(ObjectAttachMessage(vguid, pguid, seat))
|
||||
sessionLogic.general.accessContainer(vehicle)
|
||||
|
|
@ -2459,13 +2483,10 @@ class ZoningOperations(
|
|||
sessionLogic.vehicles.GetKnownVehicleAndSeat() match {
|
||||
case (Some(vehicle: Vehicle), Some(seat: Int)) =>
|
||||
//vehicle and driver/passenger
|
||||
val vdef = vehicle.Definition
|
||||
val vguid = vehicle.GUID
|
||||
val vdata = vdef.Packet.ConstructorData(vehicle).get
|
||||
sendResponse(ObjectCreateMessage(vehicle.Definition.ObjectId, vguid, vdata))
|
||||
sendResponse(OCM.apply(vehicle))
|
||||
Vehicles.ReloadAccessPermissions(vehicle, continent.id)
|
||||
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 pguid = player.GUID
|
||||
player.VehicleSeated = None
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import net.psforever.objects.vital.interaction.DamageInteraction
|
|||
import net.psforever.objects.zones.Zone
|
||||
import net.psforever.services.Service
|
||||
import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
|
||||
import net.psforever.services.local.{LocalAction, LocalServiceMessage}
|
||||
import net.psforever.types.PlanetSideEmpire
|
||||
|
||||
import scala.annotation.unused
|
||||
|
|
@ -81,8 +82,14 @@ class BoomerDeployableControl(mine: BoomerDeployable)
|
|||
}
|
||||
|
||||
override def gainOwnership(player: Player): Unit = {
|
||||
mine.Faction = PlanetSideEmpire.NEUTRAL //force map icon redraw
|
||||
val originalOwner = mine.OwnerName
|
||||
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 = {
|
||||
|
|
|
|||
|
|
@ -18,16 +18,11 @@ trait OwnableByPlayer {
|
|||
def OwnerGuid_=(owner: Player): Option[PlanetSideGUID] = OwnerGuid_=(Some(owner.GUID))
|
||||
|
||||
def OwnerGuid_=(owner: Option[PlanetSideGUID]): Option[PlanetSideGUID] = {
|
||||
owner match {
|
||||
case Some(_) =>
|
||||
ownerGuid = owner
|
||||
case None =>
|
||||
ownerGuid = None
|
||||
}
|
||||
ownerGuid = owner
|
||||
OwnerGuid
|
||||
}
|
||||
|
||||
def OwnerName: Option[String] = owner.map { _.name }
|
||||
def OwnerName: Option[String] = owner.map(_.name)
|
||||
|
||||
def OriginalOwnerName: Option[String] = originalOwnerName
|
||||
|
||||
|
|
@ -47,7 +42,7 @@ trait OwnableByPlayer {
|
|||
(originalOwnerName, playerOpt) match {
|
||||
case (None, Some(player)) =>
|
||||
owner = Some(UniquePlayer(player))
|
||||
originalOwnerName = originalOwnerName.orElse { Some(player.Name) }
|
||||
originalOwnerName = originalOwnerName.orElse(Some(player.Name))
|
||||
OwnerGuid = player
|
||||
case (_, Some(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")
|
||||
|
||||
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)
|
||||
|
||||
case Player.BuildDeployable(obj, tool) =>
|
||||
|
|
@ -534,7 +534,6 @@ class PlayerControl(player: Player, avatarActor: typed.ActorRef[AvatarActor.Comm
|
|||
deployablePair match {
|
||||
case Some((deployable, tool)) if deployable eq obj =>
|
||||
val zone = player.Zone
|
||||
//boomers
|
||||
val trigger = new BoomerTrigger
|
||||
trigger.Companion = obj.GUID
|
||||
obj.Trigger = trigger
|
||||
|
|
@ -552,7 +551,7 @@ class PlayerControl(player: Player, avatarActor: typed.ActorRef[AvatarActor.Comm
|
|||
TaskWorkflow.execute(PutNewEquipmentInInventoryOrDrop(player)(trigger))
|
||||
}
|
||||
Players.buildCooldownReset(zone, player.Name, obj)
|
||||
case _ => ;
|
||||
case _ => ()
|
||||
}
|
||||
deployablePair = None
|
||||
|
||||
|
|
@ -569,7 +568,7 @@ class PlayerControl(player: Player, avatarActor: typed.ActorRef[AvatarActor.Comm
|
|||
TelepadControl.TelepadError(zone, player.Name, msg = "@Telepad_NoDeploy_RouterLost")
|
||||
}
|
||||
Players.buildCooldownReset(zone, player.Name, obj)
|
||||
case _ => ;
|
||||
case _ => ()
|
||||
}
|
||||
deployablePair = None
|
||||
|
||||
|
|
@ -584,7 +583,7 @@ class PlayerControl(player: Player, avatarActor: typed.ActorRef[AvatarActor.Comm
|
|||
case None =>
|
||||
log.warn(s"${player.Name} should have destroyed a ${tool.Definition.Name} here, but could not find it")
|
||||
}
|
||||
case _ => ;
|
||||
case _ => ()
|
||||
}
|
||||
deployablePair = None
|
||||
|
||||
|
|
@ -701,16 +700,27 @@ class PlayerControl(player: Player, avatarActor: typed.ActorRef[AvatarActor.Comm
|
|||
if (deployables.Valid(obj) &&
|
||||
!deployables.Contains(obj) &&
|
||||
Players.deployableWithinBuildLimits(player, obj)) {
|
||||
//deployables, upon construction, may display an animation effect
|
||||
tool.Definition match {
|
||||
case GlobalDefinitions.ace | /* animation handled in deployable lifecycle */
|
||||
GlobalDefinitions.router_telepad => ; /* no special animation */
|
||||
case 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
|
||||
if obj.Definition.deployAnimation == DeployAnimation.Fdu =>
|
||||
zone.AvatarEvents ! AvatarServiceMessage(zone.id, AvatarAction.PutDownFDU(player.GUID))
|
||||
case _ =>
|
||||
org.log4s.getLogger(name = "Deployables").warn(
|
||||
s"not sure what kind of construction item to animate - ${tool.Definition.Name}"
|
||||
)
|
||||
org.log4s
|
||||
.getLogger(name = "Deployables")
|
||||
.warn(s"not sure what kind of construction item to animate - ${tool.Definition.Name}")
|
||||
}
|
||||
deployablePair = Some((obj, tool))
|
||||
obj.Faction = player.Faction
|
||||
|
|
@ -1158,10 +1168,14 @@ class PlayerControl(player: Player, avatarActor: typed.ActorRef[AvatarActor.Comm
|
|||
zone.GUID(trigger.Companion) match {
|
||||
case Some(obj: BoomerDeployable) =>
|
||||
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)
|
||||
}
|
||||
case _ => ;
|
||||
case _ => ()
|
||||
}
|
||||
|
||||
case citem: ConstructionItem
|
||||
|
|
@ -1172,7 +1186,7 @@ class PlayerControl(player: Player, avatarActor: typed.ActorRef[AvatarActor.Comm
|
|||
}
|
||||
Deployables.initializeConstructionItem(player.avatar.certifications, citem)
|
||||
|
||||
case _ => ;
|
||||
case _ => ()
|
||||
}
|
||||
events ! AvatarServiceMessage(
|
||||
toChannel,
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ package net.psforever.objects.ce
|
|||
import akka.actor.{Actor, ActorRef, Cancellable}
|
||||
import net.psforever.objects.guid.{GUIDTask, TaskWorkflow}
|
||||
import net.psforever.objects._
|
||||
import net.psforever.objects.definition.DeployAnimation
|
||||
import net.psforever.objects.zones.Zone
|
||||
import net.psforever.packet.game._
|
||||
import net.psforever.services.Service
|
||||
|
|
@ -75,7 +74,7 @@ trait DeployableBehavior {
|
|||
}
|
||||
|
||||
case Deployable.Ownership(Some(player))
|
||||
if !DeployableObject.Destroyed && DeployableObject.OwnerGuid.isEmpty =>
|
||||
if !DeployableObject.Destroyed /*&& DeployableObject.OwnerGuid.isEmpty*/ =>
|
||||
if (constructed.contains(true)) {
|
||||
gainOwnership(player)
|
||||
} else {
|
||||
|
|
@ -105,6 +104,7 @@ trait DeployableBehavior {
|
|||
def loseOwnership(obj: Deployable, toFaction: PlanetSideEmpire.Value): Unit = {
|
||||
DeployableBehavior.changeOwnership(
|
||||
obj,
|
||||
toOwner = "",
|
||||
toFaction,
|
||||
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 = {
|
||||
val obj = DeployableObject
|
||||
obj.AssignOwnership(player)
|
||||
decay.cancel()
|
||||
DeployableBehavior.changeOwnership(
|
||||
obj,
|
||||
player.Name,
|
||||
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.
|
||||
* 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.
|
||||
* @see `DeployableDefinition.deployAnimation`
|
||||
* @see `DeployableDefinition.DeployTime`
|
||||
|
|
@ -157,21 +157,9 @@ trait DeployableBehavior {
|
|||
* @param callback an `ActorRef` used for confirming the deployable's completion of the process
|
||||
*/
|
||||
def setupDeployable(callback: ActorRef): Unit = {
|
||||
import scala.concurrent.ExecutionContext.Implicits.global
|
||||
val obj = DeployableObject
|
||||
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(
|
||||
obj.Definition.DeployTime milliseconds,
|
||||
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,
|
||||
* 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.
|
||||
* @see `AvatarAction.DeployItem`
|
||||
* @see `LocalAction.DeployItem`
|
||||
* @see `DeploymentAction`
|
||||
* @see `DeployableInfo`
|
||||
* @see `LocalAction.DeployableMapIcon`
|
||||
|
|
@ -197,27 +185,22 @@ trait DeployableBehavior {
|
|||
setup = Default.Cancellable
|
||||
constructed = Some(true)
|
||||
val obj = DeployableObject
|
||||
val zone = obj.Zone
|
||||
val zone = obj.Zone
|
||||
val localEvents = zone.LocalEvents
|
||||
val owner = obj.OwnerGuid.getOrElse(Service.defaultPlayerGUID)
|
||||
obj.OwnerName match {
|
||||
case Some(_) =>
|
||||
case None =>
|
||||
import scala.concurrent.ExecutionContext.Implicits.global
|
||||
decay = context.system.scheduler.scheduleOnce(
|
||||
Deployable.decay,
|
||||
self,
|
||||
Deployable.Deconstruct()
|
||||
)
|
||||
obj.OwnerName.orElse {
|
||||
import scala.concurrent.ExecutionContext.Implicits.global
|
||||
decay = context.system.scheduler.scheduleOnce(Deployable.decay, self, Deployable.Deconstruct())
|
||||
None
|
||||
}
|
||||
//zone build
|
||||
zone.AvatarEvents ! AvatarServiceMessage(zone.id, AvatarAction.DeployItem(Service.defaultPlayerGUID, obj))
|
||||
localEvents ! LocalServiceMessage(zone.id, LocalAction.DeployItem(obj))
|
||||
//zone map icon
|
||||
localEvents ! LocalServiceMessage(
|
||||
obj.Faction.toString,
|
||||
LocalAction.DeployableMapIcon(
|
||||
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
|
||||
|
|
@ -290,28 +273,28 @@ object DeployableBehavior {
|
|||
* @param toFaction 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 zone = obj.Zone
|
||||
val localEvents = zone.LocalEvents
|
||||
if (originalFaction != toFaction) {
|
||||
val guid = obj.GUID
|
||||
val zone = obj.Zone
|
||||
val localEvents = zone.LocalEvents
|
||||
obj.Faction = toFaction
|
||||
//visual tells in regards to ownership by faction
|
||||
zone.AvatarEvents ! AvatarServiceMessage(
|
||||
zone.id,
|
||||
AvatarAction.SetEmpire(Service.defaultPlayerGUID, guid, toFaction)
|
||||
AvatarAction.SetEmpire(Service.defaultPlayerGUID, dGuid, toFaction)
|
||||
)
|
||||
//remove knowledge by the previous owner's faction
|
||||
localEvents ! LocalServiceMessage(
|
||||
originalFaction.toString,
|
||||
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,
|
||||
None,
|
||||
obj.Jammed,
|
||||
Some(true),
|
||||
None,
|
||||
None,
|
||||
obj.OwnerGuid match {
|
||||
case Some(owner) => owner
|
||||
|
|
@ -67,7 +67,7 @@ object SmallTurretConverter {
|
|||
private def MakeMountings(obj: WeaponTurret): List[InventoryItemData.InventoryItem] = {
|
||||
obj.Weapons
|
||||
.map({
|
||||
case ((index, slot)) =>
|
||||
case (index, slot) =>
|
||||
val equip: Equipment = slot.Equipment.get
|
||||
val equipDef = equip.Definition
|
||||
InventoryItemData(equipDef.ObjectId, equip.GUID, index, equipDef.Packet.ConstructorData(equip).get)
|
||||
|
|
|
|||
|
|
@ -19,10 +19,10 @@ class TRAPConverter extends ObjectCreateConverter[TrapDeployable]() {
|
|||
obj.Faction,
|
||||
bops = false,
|
||||
alternate = false,
|
||||
true,
|
||||
v1 = true,
|
||||
None,
|
||||
jammered = false,
|
||||
None,
|
||||
false,
|
||||
Some(true),
|
||||
None,
|
||||
obj.OwnerGuid match {
|
||||
case Some(owner) => owner
|
||||
|
|
@ -42,9 +42,9 @@ class TRAPConverter extends ObjectCreateConverter[TrapDeployable]() {
|
|||
obj.Faction,
|
||||
bops = false,
|
||||
alternate = true,
|
||||
true,
|
||||
v1 = true,
|
||||
None,
|
||||
false,
|
||||
jammered = false,
|
||||
Some(true),
|
||||
None,
|
||||
PlanetSideGUID(0)
|
||||
|
|
|
|||
|
|
@ -455,7 +455,7 @@ object GamePacketOpcode extends Enumeration {
|
|||
case 0x7f => game.AvatarStatisticsMessage.decode
|
||||
|
||||
// OPCODES 0x80-8f
|
||||
case 0x80 => noDecoder(GenericObjectAction2Message)
|
||||
case 0x80 => game.GenericObjectAction2Message.decode
|
||||
case 0x81 => game.DestroyDisplayMessage.decode
|
||||
case 0x82 => noDecoder(TriggerBotAction)
|
||||
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
|
||||
package net.psforever.packet.game
|
||||
|
||||
import net.psforever.packet.GamePacketOpcode.Type
|
||||
import net.psforever.packet.game.PlanetsideAttributeEnum.PlanetsideAttributeEnum
|
||||
import net.psforever.packet.{GamePacketOpcode, Marshallable, PlanetSideGamePacket}
|
||||
import net.psforever.types.PlanetSideGUID
|
||||
import scodec.Codec
|
||||
import scodec.bits.BitVector
|
||||
import scodec.{Attempt, Codec}
|
||||
import scodec.codecs._
|
||||
|
||||
/**
|
||||
|
|
@ -68,8 +70,8 @@ import scodec.codecs._
|
|||
* `17 - BEP. Value seems to be the same as BattleExperienceMessage`<br>
|
||||
* `18 - CEP.`<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".
|
||||
* Format is: Time left - 2 bytes, faction - 1 byte (1-4), isResecured - 1 byte (0-1)`<br>
|
||||
* `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>
|
||||
* <ul>
|
||||
* <li>65535 segments per faction in deciseconds (seconds * 10)</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>
|
||||
* <ul>
|
||||
* <li>0 - LFS</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>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>
|
||||
* </ul>
|
||||
* `32 - Maintain the squad role index, when a member of a squad`<br>
|
||||
* `35 - Battle Rank`<br>
|
||||
|
|
@ -204,8 +206,8 @@ import scodec.codecs._
|
|||
final case class PlanetsideAttributeMessage(guid: PlanetSideGUID, attribute_type: Int, attribute_value: Long)
|
||||
extends PlanetSideGamePacket {
|
||||
type Packet = PlanetsideAttributeMessage
|
||||
def opcode = GamePacketOpcode.PlanetsideAttributeMessage
|
||||
def encode = PlanetsideAttributeMessage.encode(this)
|
||||
def opcode: Type = GamePacketOpcode.PlanetsideAttributeMessage
|
||||
def encode: Attempt[BitVector] = PlanetsideAttributeMessage.encode(this)
|
||||
}
|
||||
|
||||
object PlanetsideAttributeMessage extends Marshallable[PlanetsideAttributeMessage] {
|
||||
|
|
@ -235,5 +237,6 @@ object PlanetsideAttributeMessage extends Marshallable[PlanetsideAttributeMessag
|
|||
object PlanetsideAttributeEnum extends Enumeration {
|
||||
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] = (
|
||||
("deploy" | CommonFieldDataWithPlacement.codec) ::
|
||||
("health" | uint8L) ::
|
||||
uint32 :: uint32 :: uint32 :: uint4L //100 bits
|
||||
uint32 ::
|
||||
uint32 ::
|
||||
uint32 ::
|
||||
uint4L
|
||||
).exmap[AegisShieldGeneratorData](
|
||||
{
|
||||
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
|
||||
("unk3" | uint4) ::
|
||||
("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] (
|
||||
{
|
||||
|
|
@ -107,7 +107,7 @@ object BattleFrameRoboticsData extends Marshallable[BattleFrameRoboticsData] {
|
|||
("unk3" | uint4) ::
|
||||
("show_bfr_shield" | 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] (
|
||||
{
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ object CaptureFlagData extends Marshallable[CaptureFlagData] {
|
|||
("targetBaseGuid" | uint8L) ::
|
||||
uint8L ::
|
||||
("milliseconds_remaining" | uint32L) ::
|
||||
uint(1)
|
||||
uint(bits = 1)
|
||||
).exmap[CaptureFlagData](
|
||||
{
|
||||
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
|
||||
("charging_pose" | bool) ::
|
||||
("unk7" | bool) :: //alternate charging pose?
|
||||
optional(bool, "on_zipline" | zipline_codec)
|
||||
("on_zipline" | optional(bool, zipline_codec))
|
||||
).exmap[CharacterAppearanceB](
|
||||
{
|
||||
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 {
|
||||
type Type = Value
|
||||
|
||||
val SurgeEffects = Value(9)
|
||||
val PersonalShieldEffects = Value(5)
|
||||
val DarklightEffects = Value(3)
|
||||
val RegenEffects = Value(0)
|
||||
val NoEffects = Value(1)
|
||||
val SurgeEffects: ImplantEffects.Value = Value(9)
|
||||
val PersonalShieldEffects: ImplantEffects.Value = Value(5)
|
||||
val DarklightEffects: ImplantEffects.Value = Value(3)
|
||||
val RegenEffects: ImplantEffects.Value = Value(0)
|
||||
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) ::
|
||||
(("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
|
||||
("command_rank" | uintL(3)) ::
|
||||
listOfN(uint2, "implant_effects" | ImplantEffects.codec) ::
|
||||
("cosmetics" | conditional(BattleRank.showCosmetics(style), Cosmetic.codec))
|
||||
("command_rank" | uint(bits = 3)) ::
|
||||
("implant_effects" | listOfN(uint2, ImplantEffects.codec)) ::
|
||||
("cosmetics" | conditional(BattleRank.showCosmetics(style), Cosmetic.codec))
|
||||
})
|
||||
).exmap[CharacterData](
|
||||
{
|
||||
|
|
@ -158,24 +158,24 @@ object CharacterData extends Marshallable[CharacterData] {
|
|||
def codec_seated(is_backpack: Boolean): Codec[CharacterData] =
|
||||
(
|
||||
("uniform_upgrade" | UniformStyle.codec) >>:~ { style =>
|
||||
uint(3) :: //uniform_upgrade is actually interpreted as a 6u field, but the lower 3u seems to be discarded
|
||||
("command_rank" | uintL(3)) ::
|
||||
listOfN(uint2, "implant_effects" | ImplantEffects.codec) ::
|
||||
("cosmetics" | conditional(BattleRank.showCosmetics(style), Cosmetic.codec))
|
||||
uint(bits = 3) :: //uniform_upgrade is actually interpreted as a 6u field, but the lower 3u seems to be discarded
|
||||
("command_rank" | uintL(bits = 3)) ::
|
||||
("implant_effects" | listOfN(uint2, ImplantEffects.codec)) ::
|
||||
("cosmetics" | conditional(BattleRank.showCosmetics(style), Cosmetic.codec))
|
||||
}
|
||||
).exmap[CharacterData](
|
||||
{
|
||||
case uniform :: unk :: cr :: implant_effects :: cosmetics :: HNil =>
|
||||
Attempt.Successful(
|
||||
new CharacterData(
|
||||
100,
|
||||
0,
|
||||
health = 100,
|
||||
armor = 0,
|
||||
uniform,
|
||||
unk,
|
||||
cr,
|
||||
implant_effects,
|
||||
cosmetics
|
||||
)(is_backpack, true)
|
||||
)(is_backpack, is_seated = true)
|
||||
)
|
||||
|
||||
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
|
||||
*/
|
||||
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 =
|
||||
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 =
|
||||
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 =
|
||||
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 =
|
||||
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(
|
||||
faction: PlanetSideEmpire.Value,
|
||||
|
|
@ -95,7 +95,7 @@ object CommonFieldData extends Marshallable[CommonFieldData] {
|
|||
unk: Int,
|
||||
player_guid: PlanetSideGUID
|
||||
): 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(
|
||||
faction: PlanetSideEmpire.Value,
|
||||
|
|
@ -107,7 +107,7 @@ object CommonFieldData extends Marshallable[CommonFieldData] {
|
|||
): CommonFieldData = {
|
||||
val jammeredField = if (jammered) { Some(0) }
|
||||
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] =
|
||||
|
|
@ -116,9 +116,9 @@ object CommonFieldData extends Marshallable[CommonFieldData] {
|
|||
("bops" | bool) ::
|
||||
("alternate" | bool) ::
|
||||
("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) ::
|
||||
optional(bool, "v5" | uint16L) ::
|
||||
("v5" | optional(bool, uint16L)) ::
|
||||
("guid" | PlanetSideGUID.codec)
|
||||
).xmap[CommonFieldData](
|
||||
{
|
||||
|
|
@ -139,9 +139,9 @@ object CommonFieldData extends Marshallable[CommonFieldData] {
|
|||
("bops" | bool) ::
|
||||
("alternate" | bool) ::
|
||||
("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) ::
|
||||
optional(bool, "v5" | uint16L) ::
|
||||
("v5" | optional(bool, uint16L)) ::
|
||||
("v4" | bool) ::
|
||||
("guid" | PlanetSideGUID.codec)
|
||||
).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 = {
|
||||
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
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ final case class ImplantEntry(implant: ImplantType, initialization: Option[Int],
|
|||
extends StreamBitSize {
|
||||
override def bitsize: Long = {
|
||||
val timerSize = initialization match {
|
||||
case Some(_) => 8L;
|
||||
case Some(_) => 8L
|
||||
case None => 1L
|
||||
}
|
||||
9L + timerSize
|
||||
|
|
@ -271,7 +271,7 @@ object DetailedCharacterData extends Marshallable[DetailedCharacterData] {
|
|||
private val implant_entry_codec: Codec[ImplantEntry] = (
|
||||
("implant" | uint8L) ::
|
||||
(bool >>:~ { guard =>
|
||||
newcodecs.binary_choice(guard, uint(1), uint8L).hlist
|
||||
newcodecs.binary_choice(guard, uint(bits = 1), uint8L).hlist
|
||||
})
|
||||
).xmap[ImplantEntry](
|
||||
{
|
||||
|
|
@ -305,7 +305,7 @@ object DetailedCharacterData extends Marshallable[DetailedCharacterData] {
|
|||
(
|
||||
uint8 >>:~ { 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]](
|
||||
{
|
||||
|
|
@ -376,7 +376,7 @@ object DetailedCharacterData extends Marshallable[DetailedCharacterData] {
|
|||
* `Codec` for a `ImprintingProgress` object.
|
||||
*/
|
||||
private val imprint_progress_codec: Codec[ImprintingProgress] = (
|
||||
uint(5) ::
|
||||
uint(bits = 5) ::
|
||||
uint8L
|
||||
).as[ImprintingProgress]
|
||||
|
||||
|
|
@ -464,7 +464,7 @@ object DetailedCharacterData extends Marshallable[DetailedCharacterData] {
|
|||
def paddingCalculations(contextOffset: Option[Int], implants: List[ImplantEntry], prevLists: List[List[Any]])(
|
||||
currListLen: Long
|
||||
): 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) ::
|
||||
conditional(suit == ExoSuitType.MAX, uint32L) ::
|
||||
("unk6" | uint16L) ::
|
||||
("unk7" | uint(3)) ::
|
||||
("unk7" | uint(bits = 3)) ::
|
||||
("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))
|
||||
).exmap[DetailedCharacterA](
|
||||
{
|
||||
|
|
@ -591,7 +591,7 @@ object DetailedCharacterData extends Marshallable[DetailedCharacterData] {
|
|||
|
||||
def b_codec(bep: Long, pad_length: Option[Int]): Codec[DetailedCharacterB] =
|
||||
(
|
||||
optional(bool, "unk1" | uint32L) ::
|
||||
("unk1" | optional(bool, uint32L)) ::
|
||||
(("implants" | PacketHelpers.listOfNSized(
|
||||
BattleRank.withExperience(bep).implantSlots,
|
||||
implant_entry_codec
|
||||
|
|
@ -607,17 +607,17 @@ object DetailedCharacterData extends Marshallable[DetailedCharacterData] {
|
|||
("unk6" | uint32L) ::
|
||||
("unk7" | uint32L) ::
|
||||
("unk8" | uint32L) ::
|
||||
(optional(isFalse, "imprinting" | imprint_progress_codec) >>:~ { imprinting =>
|
||||
(("imprinting" | optional(isFalse, imprint_progress_codec)) >>:~ { imprinting =>
|
||||
("unkA" | listOfN(uint16L, uint32L)) ::
|
||||
("unkB" | unkBCodec(
|
||||
paddingCalculations(
|
||||
displaceByOptionTest(pad_length, imprinting, 5),
|
||||
displaceByOptionTest(pad_length, imprinting, value = 5),
|
||||
implants,
|
||||
List(imprinting.toList, tut, fte, unk3, unk2)
|
||||
)
|
||||
)) ::
|
||||
("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)
|
||||
|
||||
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)
|
||||
("mode" | uint16) ::
|
||||
uint2 ::
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ object DetailedPlayerData extends Marshallable[DetailedPlayerData] {
|
|||
drawn_slot: DrawnSlot.Value
|
||||
): DetailedPlayerData = {
|
||||
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
|
||||
): DetailedPlayerData = {
|
||||
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
|
||||
): DetailedPlayerData = {
|
||||
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
|
||||
): DetailedPlayerData = {
|
||||
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] =
|
||||
(conditional(position_defined, "pos" | PlacementData.codec) >>:~ { pos =>
|
||||
("basic_appearance" | CharacterAppearanceData.codec(PlayerData.PaddingOffset(pos))) >>:~ { app =>
|
||||
("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) ::
|
||||
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 ::
|
||||
uint4L ::
|
||||
("unk" | uint8) ::
|
||||
uint(7)
|
||||
uint(bits = 7)
|
||||
).exmap[DetailedREKData](
|
||||
{
|
||||
case data :: 2 :: 0 :: 8 :: unk :: 0 :: HNil =>
|
||||
|
|
|
|||
|
|
@ -56,11 +56,11 @@ object DetailedWeaponData extends Marshallable[DetailedWeaponData] {
|
|||
DetailedWeaponData(
|
||||
CommonFieldData(
|
||||
PlanetSideEmpire(unk1 & 3),
|
||||
false,
|
||||
false,
|
||||
(unk2 & 8) == 8,
|
||||
bops = false,
|
||||
alternate = false,
|
||||
v1 = (unk2 & 8) == 8,
|
||||
None,
|
||||
(unk2 & 4) == 4,
|
||||
jammered = (unk2 & 4) == 4,
|
||||
None,
|
||||
None,
|
||||
PlanetSideGUID(0)
|
||||
|
|
@ -92,11 +92,11 @@ object DetailedWeaponData extends Marshallable[DetailedWeaponData] {
|
|||
DetailedWeaponData(
|
||||
CommonFieldData(
|
||||
PlanetSideEmpire(unk1 & 3),
|
||||
false,
|
||||
false,
|
||||
(unk2 & 8) == 8,
|
||||
bops = false,
|
||||
alternate = false,
|
||||
v1 = (unk2 & 8) == 8,
|
||||
None,
|
||||
(unk2 & 4) == 4,
|
||||
jammered = (unk2 & 4) == 4,
|
||||
None,
|
||||
None,
|
||||
PlanetSideGUID(0)
|
||||
|
|
@ -112,7 +112,7 @@ object DetailedWeaponData extends Marshallable[DetailedWeaponData] {
|
|||
uint8 ::
|
||||
("fire_mode" | uint8) ::
|
||||
uint2 ::
|
||||
optional(bool, "ammo" | InventoryData.codec_detailed) ::
|
||||
("ammo" | optional(bool, InventoryData.codec_detailed)) ::
|
||||
("unk" | bool)
|
||||
).exmap[DetailedWeaponData](
|
||||
{
|
||||
|
|
|
|||
|
|
@ -46,9 +46,9 @@ object DroppodData extends Marshallable[DroppodData] {
|
|||
("basic" | CommonFieldDataWithPlacement.codec) ::
|
||||
bool ::
|
||||
("health" | uint8L) :: //health
|
||||
uintL(5) :: //0x0
|
||||
uintL(bits = 5) :: //0x0
|
||||
uint4L :: //0xF
|
||||
uintL(6) :: //0x0
|
||||
uintL(bits = 6) :: //0x0
|
||||
("boosters" | uint4L) :: //0x9 on standby, 0x0 when burning and occupied (basic.player_guid?)
|
||||
("unk" | bool)
|
||||
).exmap[DroppodData](
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ object HandheldData extends Marshallable[HandheldData] {
|
|||
implicit val codec: Codec[HandheldData] = (
|
||||
("data" | CommonFieldData.codec) ::
|
||||
("mode" | uint8) ::
|
||||
("unk" | uint(3))
|
||||
("unk" | uint(bits = 3))
|
||||
).exmap[HandheldData](
|
||||
{
|
||||
case data :: mode :: unk :: HNil =>
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ object InternalSlot {
|
|||
* Used for `0x18` `ObjectCreateDetailedMessage` packets
|
||||
*/
|
||||
val codec_detailed: Codec[InternalSlot] = (
|
||||
("objectClass" | uintL(11)) >>:~ { obj_cls =>
|
||||
("objectClass" | uintL(bits = 11)) >>:~ { obj_cls =>
|
||||
("guid" | PlanetSideGUID.codec) ::
|
||||
("parentSlot" | PacketHelpers.encodedStringSize) ::
|
||||
("obj" | ObjectClass.selectDataDetailedCodec(obj_cls)) //it's fine for this call to fail
|
||||
|
|
@ -57,7 +57,7 @@ object InternalSlot {
|
|||
* Used for `0x17` `ObjectCreateMessage` packets
|
||||
*/
|
||||
val codec: Codec[InternalSlot] = (
|
||||
("objectClass" | uintL(11)) >>:~ { obj_cls =>
|
||||
("objectClass" | uintL(bits = 11)) >>:~ { obj_cls =>
|
||||
("guid" | PlanetSideGUID.codec) ::
|
||||
("parentSlot" | PacketHelpers.encodedStringSize) ::
|
||||
("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] = (
|
||||
("deploy" | CommonFieldDataWithPlacement.codec2) ::
|
||||
("health" | uint8L) ::
|
||||
uintL(7) ::
|
||||
uintL(bits = 7) ::
|
||||
uint4L ::
|
||||
uint2L ::
|
||||
optional(bool, "internals" | InventoryData.codec)
|
||||
("internals" | optional(bool, InventoryData.codec))
|
||||
).exmap[LargeDeployableData](
|
||||
{
|
||||
case deploy :: health :: 0 :: 0xf :: 0 :: internals :: HNil =>
|
||||
|
|
|
|||
|
|
@ -31,9 +31,11 @@ object LockerContainerData extends Marshallable[LockerContainerData] {
|
|||
new LockerContainerData(Some(InventoryData(inventory)))
|
||||
|
||||
implicit val codec: Codec[LockerContainerData] = (
|
||||
uint32 :: uint32 :: uint(17) ::
|
||||
uint32 ::
|
||||
uint32 ::
|
||||
uint(bits = 17) ::
|
||||
uint2L ::
|
||||
uint(21) ::
|
||||
uint(bits = 21) ::
|
||||
("inventory" | optional(bool, InventoryData.codec))
|
||||
).exmap[LockerContainerData](
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1216,22 +1216,21 @@ object ObjectClass {
|
|||
case ObjectClass.advanced_ace => DroppedItemData(HandheldData.codec, "advanced ace")
|
||||
case ObjectClass.router_telepad => DroppedItemData(HandheldData.codec, "router telepad")
|
||||
case ObjectClass.boomer_trigger => DroppedItemData(HandheldData.codec, "boomer trigger")
|
||||
case ObjectClass.boomer => ConstructorData(CommonFieldDataWithPlacement.codec2, "ace deployable")
|
||||
case ObjectClass.he_mine => ConstructorData(CommonFieldDataWithPlacement.codec2, "ace deployable")
|
||||
case ObjectClass.jammer_mine => ConstructorData(CommonFieldDataWithPlacement.codec2, "ace deployable")
|
||||
case ObjectClass.motionalarmsensor => ConstructorData(CommonFieldDataWithPlacement.codec2, "ace deployable")
|
||||
case ObjectClass.sensor_shield => ConstructorData(CommonFieldDataWithPlacement.codec2, "ace deployable")
|
||||
case ObjectClass.boomer => ConstructorData(CommonFieldDataWithPlacement.codec, "ace deployable")
|
||||
case ObjectClass.he_mine => ConstructorData(CommonFieldDataWithPlacement.codec, "ace deployable")
|
||||
case ObjectClass.jammer_mine => ConstructorData(CommonFieldDataWithPlacement.codec, "ace deployable")
|
||||
case ObjectClass.motionalarmsensor => ConstructorData(CommonFieldDataWithPlacement.codec, "ace deployable")
|
||||
case ObjectClass.sensor_shield => ConstructorData(CommonFieldDataWithPlacement.codec, "ace deployable")
|
||||
case ObjectClass.spitfire_aa => 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.tank_traps => ConstructorData(TRAPData.codec, "trap")
|
||||
case ObjectClass.deployable_shield_generator =>
|
||||
ConstructorData(AegisShieldGeneratorData.codec, "shield generator")
|
||||
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_tr => 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.deployable_shield_generator => ConstructorData(AegisShieldGeneratorData.codec, "shield generator")
|
||||
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_tr => 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")
|
||||
//projectiles
|
||||
case ObjectClass.aphelion_plasma_cloud => ConstructorData(RadiationCloudData.codec, "radiation cloud")
|
||||
case ObjectClass.aphelion_starfire_projectile => ConstructorData(RemoteProjectileData.codec, "projectile")
|
||||
|
|
|
|||
|
|
@ -39,7 +39,6 @@ final case class OneMannedFieldTurretData(
|
|||
}
|
||||
|
||||
object OneMannedFieldTurretData extends Marshallable[OneMannedFieldTurretData] {
|
||||
|
||||
/**
|
||||
* 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
|
||||
|
|
@ -55,10 +54,10 @@ object OneMannedFieldTurretData extends Marshallable[OneMannedFieldTurretData] {
|
|||
PlanetSideGUID.codec :: //hoist/extract with the deploy.owner_guid in field above
|
||||
bool ::
|
||||
("health" | uint8L) ::
|
||||
uint(5) ::
|
||||
uint(bits = 5) ::
|
||||
uint4 ::
|
||||
uint2 ::
|
||||
optional(bool, "internals" | InventoryData.codec)
|
||||
("internals" | optional(bool, InventoryData.codec))
|
||||
).exmap[OneMannedFieldTurretData](
|
||||
{
|
||||
case deploy :: player :: false :: health :: 0 :: 0xf :: 0 :: internals :: HNil =>
|
||||
|
|
|
|||
|
|
@ -58,9 +58,9 @@ object OrbitalShuttleData extends Marshallable[OrbitalShuttleData] {
|
|||
|
||||
implicit val codec: Codec[OrbitalShuttleData] = (
|
||||
("faction" | PlanetSideEmpire.codec) ::
|
||||
uintL(25) ::
|
||||
uintL(bits = 25) ::
|
||||
uint8L :: //255
|
||||
uintL(5) ::
|
||||
uintL(bits = 5) ::
|
||||
uint4L :: //7
|
||||
uint2L
|
||||
).exmap[OrbitalShuttleData](
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ object PlayerData extends Marshallable[PlayerData] {
|
|||
): PlayerData = {
|
||||
val appearance = basic_appearance(5)
|
||||
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
|
||||
): PlayerData = {
|
||||
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),
|
||||
Some(inventory),
|
||||
drawn_slot
|
||||
)(true)
|
||||
)(position_defined = true)
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -144,7 +144,7 @@ object PlayerData extends Marshallable[PlayerData] {
|
|||
drawn_slot: DrawnSlot.Type
|
||||
): PlayerData = {
|
||||
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_seated(app.b.backpack)
|
||||
)) ::
|
||||
optional(bool, "inventory" | InventoryData.codec) ::
|
||||
("inventory" | optional(bool, InventoryData.codec)) ::
|
||||
("drawn_slot" | DrawnSlot.codec) ::
|
||||
bool //usually false
|
||||
}
|
||||
|
|
@ -232,14 +232,14 @@ object PlayerData extends Marshallable[PlayerData] {
|
|||
(
|
||||
("basic_appearance" | CharacterAppearanceData.codec(offset)) >>:~ { app =>
|
||||
("character_data" | CharacterData.codec_seated(app.b.backpack)) ::
|
||||
optional(bool, "inventory" | InventoryData.codec) ::
|
||||
("inventory" | optional(bool, InventoryData.codec)) ::
|
||||
("drawn_slot" | DrawnSlot.codec) ::
|
||||
bool //usually false
|
||||
}
|
||||
).xmap[PlayerData](
|
||||
{
|
||||
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) =>
|
||||
|
|
@ -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] = (
|
||||
("data" | CommonFieldData.codec2) ::
|
||||
("unk1" | uint16) ::
|
||||
("unk2" | uint(10))
|
||||
("unk2" | uint(bits = 10))
|
||||
).exmap[REKData](
|
||||
{
|
||||
case data :: u1 :: u2 :: HNil =>
|
||||
|
|
|
|||
|
|
@ -26,19 +26,19 @@ object FlightPhysics extends Enumeration {
|
|||
type Type = Value
|
||||
|
||||
//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)
|
||||
val State4 = Value(4)
|
||||
val State4: FlightPhysics.Value = Value(4)
|
||||
//valid(infinite)
|
||||
val State5 = Value(5)
|
||||
val State5: FlightPhysics.Value = Value(5)
|
||||
//valid (uses velocity) (infinite)
|
||||
val State6 = Value(6)
|
||||
val State6: FlightPhysics.Value = Value(6)
|
||||
//valid (uses velocity) (infinite)
|
||||
val State7 = Value(7)
|
||||
val State7: FlightPhysics.Value = Value(7)
|
||||
//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 =>
|
||||
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))
|
||||
|
||||
implicit val codec: Codec[SmallTurretData] = (
|
||||
("deploy" | CommonFieldDataWithPlacement.codec2) ::
|
||||
("deploy" | CommonFieldDataWithPlacement.codec) ::
|
||||
ignore(size = 1) ::
|
||||
("health" | uint8L) ::
|
||||
uintL(7) ::
|
||||
uintL(bits = 7) ::
|
||||
uint4L ::
|
||||
uint2L ::
|
||||
optional(bool, "internals" | InventoryData.codec)
|
||||
("internals" | optional(bool, InventoryData.codec))
|
||||
).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) {
|
||||
(0, None)
|
||||
} else {
|
||||
|
|
@ -75,7 +76,7 @@ object SmallTurretData extends Marshallable[SmallTurretData] {
|
|||
} else {
|
||||
(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 {
|
||||
override def bitsize: Long = {
|
||||
22L + deploy.bitsize //8u + 7u + 4u + 3u
|
||||
23L + deploy.bitsize //1u + 8u + 7u + 4u + 3u
|
||||
}
|
||||
}
|
||||
|
||||
object TRAPData extends Marshallable[TRAPData] {
|
||||
implicit val codec: Codec[TRAPData] = (
|
||||
("deploy" | CommonFieldDataWithPlacement.codec2) ::
|
||||
("deploy" | CommonFieldDataWithPlacement.codec) ::
|
||||
ignore(size = 1) ::
|
||||
("health" | uint8L) ::
|
||||
uint(7) ::
|
||||
uint(bits = 7) ::
|
||||
uint4L ::
|
||||
uint(3)
|
||||
uint(bits = 3)
|
||||
).exmap[TRAPData](
|
||||
{
|
||||
case deploy :: health :: 0 :: 15 :: 0 :: HNil =>
|
||||
case deploy :: _:: health :: 0 :: 15 :: 0 :: HNil =>
|
||||
Attempt.successful(TRAPData(deploy, health))
|
||||
|
||||
case data =>
|
||||
|
|
@ -35,7 +36,7 @@ object TRAPData extends Marshallable[TRAPData] {
|
|||
},
|
||||
{
|
||||
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,
|
||||
inventory: Option[InventoryData]
|
||||
): 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
|
||||
)
|
||||
}
|
||||
|
|
@ -128,7 +128,7 @@ object VehicleData extends Marshallable[VehicleData] {
|
|||
format: UtilityVehicleData,
|
||||
inventory: Option[InventoryData]
|
||||
): 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
|
||||
)
|
||||
}
|
||||
|
|
@ -150,7 +150,7 @@ object VehicleData extends Marshallable[VehicleData] {
|
|||
format: VariantVehicleData,
|
||||
inventory: Option[InventoryData]
|
||||
): 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
|
||||
)
|
||||
}
|
||||
|
|
@ -227,8 +227,8 @@ object VehicleData extends Marshallable[VehicleData] {
|
|||
("unk5" | bool) :: //unknown but generally false; can cause stream misalignment if set when unexpectedly
|
||||
("unk6" | bool) ::
|
||||
("cloak" | bool) :: //cloak as wraith, phantasm
|
||||
conditional(vehicle_type != VehicleFormat.Normal,"vehicle_format_data" | selectFormatReader(vehicle_type)) ::
|
||||
optional(bool, target = "inventory" | MountableInventory.custom_inventory_codec(pos.vel.isDefined, vehicle_type))
|
||||
("vehicle_format_data" | conditional(vehicle_type != VehicleFormat.Normal, selectFormatReader(vehicle_type))) ::
|
||||
("inventory" | optional(bool, MountableInventory.custom_inventory_codec(pos.vel.isDefined, vehicle_type)))
|
||||
}
|
||||
).exmap[VehicleData](
|
||||
{
|
||||
|
|
|
|||
|
|
@ -54,8 +54,8 @@ object WeaponData extends Marshallable[WeaponData] {
|
|||
WeaponData(
|
||||
CommonFieldData(
|
||||
PlanetSideEmpire(unk1 & 3),
|
||||
false,
|
||||
false,
|
||||
bops = false,
|
||||
alternate = false,
|
||||
(unk2 & 8) == 8,
|
||||
None,
|
||||
(unk2 & 4) == 4,
|
||||
|
|
@ -91,8 +91,8 @@ object WeaponData extends Marshallable[WeaponData] {
|
|||
WeaponData(
|
||||
CommonFieldData(
|
||||
PlanetSideEmpire(unk1 & 3),
|
||||
false,
|
||||
false,
|
||||
bops = false,
|
||||
alternate = false,
|
||||
(unk2 & 8) == 8,
|
||||
None,
|
||||
(unk2 & 4) == 4,
|
||||
|
|
@ -137,8 +137,8 @@ object WeaponData extends Marshallable[WeaponData] {
|
|||
WeaponData(
|
||||
CommonFieldData(
|
||||
PlanetSideEmpire(unk1 & 3),
|
||||
false,
|
||||
false,
|
||||
bops = false,
|
||||
alternate = false,
|
||||
(unk2 & 8) == 8,
|
||||
None,
|
||||
(unk2 & 4) == 4,
|
||||
|
|
|
|||
|
|
@ -87,17 +87,6 @@ class AvatarService(zone: Zone) extends Actor {
|
|||
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) =>
|
||||
AvatarEvents.publish(
|
||||
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.avatar.scoring.KDAStat
|
||||
import net.psforever.objects.ballistics.Projectile
|
||||
import net.psforever.objects.ce.Deployable
|
||||
import net.psforever.objects.equipment.Equipment
|
||||
import net.psforever.objects.inventory.InventoryItem
|
||||
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 EnvironmentalDamage(player_guid: PlanetSideGUID, source_guid: PlanetSideGUID, amount: Int)
|
||||
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 ActivateImplantSlot(player_guid: PlanetSideGUID, slot: Int) extends Action
|
||||
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 net.psforever.objects.serverobject.terminals.Terminal
|
||||
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.types.PlanetSideGUID
|
||||
import net.psforever.services.local.support._
|
||||
|
|
@ -45,6 +45,16 @@ class LocalService(zone: Zone) extends Actor {
|
|||
|
||||
case LocalServiceMessage(forChannel, action) =>
|
||||
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) =>
|
||||
LocalEvents.publish(
|
||||
LocalServiceResponse(
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ object LocalServiceMessage {
|
|||
object LocalAction {
|
||||
trait Action
|
||||
|
||||
final case class DeployItem(item: Deployable) extends Action
|
||||
final case class DeployableMapIcon(
|
||||
player_guid: PlanetSideGUID,
|
||||
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.v2.isEmpty mustEqual true
|
||||
deploy.jammered mustEqual false
|
||||
deploy.v4.contains(false) mustEqual true
|
||||
deploy.v4.isEmpty mustEqual true
|
||||
deploy.v5.isEmpty mustEqual true
|
||||
deploy.guid mustEqual PlanetSideGUID(7742)
|
||||
deploy.guid mustEqual PlanetSideGUID(3871)
|
||||
|
||||
health mustEqual 0
|
||||
case _ =>
|
||||
|
|
@ -63,9 +63,9 @@ class SmallTurretDataTest extends Specification {
|
|||
deploy.v1 mustEqual true
|
||||
deploy.v2.isEmpty mustEqual true
|
||||
deploy.jammered mustEqual false
|
||||
deploy.v4.contains(true) mustEqual true
|
||||
deploy.v4.isEmpty mustEqual true
|
||||
deploy.v5.isEmpty mustEqual true
|
||||
deploy.guid mustEqual PlanetSideGUID(8208)
|
||||
deploy.guid mustEqual PlanetSideGUID(4232)
|
||||
|
||||
health mustEqual 255
|
||||
|
||||
|
|
@ -124,7 +124,7 @@ class SmallTurretDataTest extends Specification {
|
|||
val obj = SmallTurretData(
|
||||
CommonFieldDataWithPlacement(
|
||||
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
|
||||
)
|
||||
|
|
@ -137,7 +137,7 @@ class SmallTurretDataTest extends Specification {
|
|||
val obj = SmallTurretData(
|
||||
CommonFieldDataWithPlacement(
|
||||
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,
|
||||
InventoryData(
|
||||
|
|
@ -149,11 +149,11 @@ class SmallTurretDataTest extends Specification {
|
|||
WeaponData(
|
||||
CommonFieldData(
|
||||
PlanetSideEmpire.NEUTRAL,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
bops = false,
|
||||
alternate = false,
|
||||
v1 = true,
|
||||
None,
|
||||
false,
|
||||
jammered = false,
|
||||
None,
|
||||
None,
|
||||
PlanetSideGUID(0)
|
||||
|
|
@ -166,11 +166,11 @@ class SmallTurretDataTest extends Specification {
|
|||
0,
|
||||
CommonFieldData(
|
||||
PlanetSideEmpire.NEUTRAL,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
bops = false,
|
||||
alternate = false,
|
||||
v1 = true,
|
||||
None,
|
||||
false,
|
||||
jammered = false,
|
||||
Some(false),
|
||||
None,
|
||||
PlanetSideGUID(0)
|
||||
|
|
|
|||
|
|
@ -29,9 +29,9 @@ class TRAPDataTest extends Specification {
|
|||
deploy.v1 mustEqual true
|
||||
deploy.v2.isEmpty mustEqual true
|
||||
deploy.jammered mustEqual false
|
||||
deploy.v4.contains(true) mustEqual true
|
||||
deploy.v4.isEmpty mustEqual true
|
||||
deploy.v5.isEmpty mustEqual true
|
||||
deploy.guid mustEqual PlanetSideGUID(4748)
|
||||
deploy.guid mustEqual PlanetSideGUID(2502)
|
||||
health mustEqual 255
|
||||
case _ =>
|
||||
ko
|
||||
|
|
@ -45,7 +45,7 @@ class TRAPDataTest extends Specification {
|
|||
val obj = TRAPData(
|
||||
CommonFieldDataWithPlacement(
|
||||
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
|
||||
)
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ class DeployableBehaviorSetupTest extends ActorTest {
|
|||
case _ => assert(false, "self-setup test - no spawn fx")
|
||||
}
|
||||
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")
|
||||
case _ =>
|
||||
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")
|
||||
}
|
||||
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")
|
||||
case _ =>
|
||||
assert( false, "owned setup test, 2 - wrong deploy message")
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ class TelepadDeployableNoRouterTest extends ActorTest {
|
|||
|
||||
val eventsMsgs = eventsProbe.receiveN(4, 10.seconds)
|
||||
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")
|
||||
case _ =>
|
||||
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)
|
||||
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")
|
||||
case _ =>
|
||||
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 routerMsgs = routerProbe.receiveN(1, 10.seconds)
|
||||
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")
|
||||
case _ =>
|
||||
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)
|
||||
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")
|
||||
case _ =>
|
||||
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 {
|
||||
ServiceManager.boot(system)
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue