diff --git a/server/src/test/scala/actor/service/AvatarServiceTest.scala b/server/src/test/scala/actor/service/AvatarServiceTest.scala
index 665c7ec7d..6e0eab30d 100644
--- a/server/src/test/scala/actor/service/AvatarServiceTest.scala
+++ b/server/src/test/scala/actor/service/AvatarServiceTest.scala
@@ -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")
diff --git a/src/main/scala/net/psforever/actors/session/support/GeneralOperations.scala b/src/main/scala/net/psforever/actors/session/support/GeneralOperations.scala
index 9f3961911..deea975f9 100644
--- a/src/main/scala/net/psforever/actors/session/support/GeneralOperations.scala
+++ b/src/main/scala/net/psforever/actors/session/support/GeneralOperations.scala
@@ -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))
}
/**
diff --git a/src/main/scala/net/psforever/objects/avatar/PlayerControl.scala b/src/main/scala/net/psforever/objects/avatar/PlayerControl.scala
index 4245c7688..b9cdf30cd 100644
--- a/src/main/scala/net/psforever/objects/avatar/PlayerControl.scala
+++ b/src/main/scala/net/psforever/objects/avatar/PlayerControl.scala
@@ -531,6 +531,7 @@ class PlayerControl(player: Player, avatarActor: typed.ActorRef[AvatarActor.Comm
setupDeployable(obj, tool)
case Zone.Deployable.IsBuilt(obj: BoomerDeployable) =>
+ obj.Actor ! Deployable.Ownership(player)
deployablePair match {
case Some((deployable, tool)) if deployable eq obj =>
val zone = player.Zone
@@ -552,11 +553,12 @@ class PlayerControl(player: Player, avatarActor: typed.ActorRef[AvatarActor.Comm
TaskWorkflow.execute(PutNewEquipmentInInventoryOrDrop(player)(trigger))
}
Players.buildCooldownReset(zone, player.Name, obj)
- case _ => ;
+ case _ => ()
}
deployablePair = None
case Zone.Deployable.IsBuilt(obj: TelepadDeployable) =>
+ obj.Actor ! Deployable.Ownership(player)
deployablePair match {
case Some((deployable, tool: Telepad)) if deployable eq obj =>
RemoveOldEquipmentFromInventory(player)(tool)
@@ -569,11 +571,12 @@ 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
case Zone.Deployable.IsBuilt(obj) =>
+ obj.Actor ! Deployable.Ownership(player)
deployablePair match {
case Some((deployable, tool)) if deployable eq obj =>
Players.buildCooldownReset(player.Zone, player.Name, obj)
@@ -584,7 +587,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 +704,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
diff --git a/src/main/scala/net/psforever/objects/ce/DeployableBehavior.scala b/src/main/scala/net/psforever/objects/ce/DeployableBehavior.scala
index 21e17818e..bbc052b5a 100644
--- a/src/main/scala/net/psforever/objects/ce/DeployableBehavior.scala
+++ b/src/main/scala/net/psforever/objects/ce/DeployableBehavior.scala
@@ -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
@@ -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, 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,27 +273,44 @@ 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
+ val ownershipAction = {
+ val owner = info.player_guid
+ LocalAction.SendPlanetsideAttributeMessage(
+ owner,
+ owner,
+ PlanetsideAttributeEnum.OwnershipAssignment,
+ dGuid.guid.toLong
+ )
+ }
if (originalFaction != toFaction) {
obj.Faction = toFaction
//visual tells in regards to ownership by faction
zone.AvatarEvents ! AvatarServiceMessage(
zone.id,
- AvatarAction.SetEmpire(Service.defaultPlayerGUID, obj.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)
)
+ } else {
+ //old owner no longer owner
+ obj.OwnerName.collect { case fromOwner if !fromOwner.equals(toOwner) =>
+ localEvents ! LocalServiceMessage(fromOwner, ownershipAction)
+ }
}
//display to the given faction
localEvents ! LocalServiceMessage(
toFaction.toString,
LocalAction.DeployableMapIcon(Service.defaultPlayerGUID, DeploymentAction.Build, info)
)
+ //new owner is owner
+ localEvents ! LocalServiceMessage(toOwner, ownershipAction)
}
}
diff --git a/src/main/scala/net/psforever/packet/game/PlanetsideAttributeMessage.scala b/src/main/scala/net/psforever/packet/game/PlanetsideAttributeMessage.scala
index a6fb90707..aaf908d14 100644
--- a/src/main/scala/net/psforever/packet/game/PlanetsideAttributeMessage.scala
+++ b/src/main/scala/net/psforever/packet/game/PlanetsideAttributeMessage.scala
@@ -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`
* `18 - CEP.`
* `19 - Anchors. Value is 0 to disengage, 1 to engage.`
- * `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)`
+ * `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)
*