mirror of
https://github.com/psforever/PSF-LoginServer.git
synced 2026-01-19 18:44:45 +00:00
Graverobbing (#490)
* added corpse control to manage (only) looting; swapping controls in ZonePopulationActor * making test timing more forgiving; fixing case conditions for corpse addition
This commit is contained in:
parent
cf64a0ba7f
commit
3ea51d404e
|
|
@ -0,0 +1,76 @@
|
|||
// Copyright (c) 2020 PSForever
|
||||
package net.psforever.objects.avatar
|
||||
|
||||
import akka.actor.Actor
|
||||
import net.psforever.objects.Player
|
||||
import net.psforever.objects.equipment.Equipment
|
||||
import net.psforever.objects.serverobject.containable.{Containable, ContainableBehavior}
|
||||
import net.psforever.packet.game.{ObjectAttachMessage, ObjectCreateDetailedMessage, ObjectDetachMessage}
|
||||
import net.psforever.packet.game.objectcreate.ObjectCreateMessageParent
|
||||
import net.psforever.types.{PlanetSideEmpire, Vector3}
|
||||
import services.Service
|
||||
import services.avatar.{AvatarAction, AvatarServiceMessage}
|
||||
|
||||
class CorpseControl(player : Player) extends Actor
|
||||
with ContainableBehavior {
|
||||
def ContainerObject = player
|
||||
|
||||
//private [this] val log = org.log4s.getLogger(player.Name)
|
||||
|
||||
def receive : Receive = containerBehavior.orElse { case _ => ; }
|
||||
|
||||
def MessageDeferredCallback(msg : Any) : Unit = {
|
||||
msg match {
|
||||
case Containable.MoveItem(_, item, _) =>
|
||||
//momentarily put item back where it was originally
|
||||
val obj = ContainerObject
|
||||
obj.Find(item) match {
|
||||
case Some(slot) =>
|
||||
obj.Zone.AvatarEvents ! AvatarServiceMessage(
|
||||
player.Zone.Id,
|
||||
AvatarAction.SendResponse(Service.defaultPlayerGUID, ObjectAttachMessage(obj.GUID, item.GUID, slot))
|
||||
)
|
||||
case None => ;
|
||||
}
|
||||
case _ => ;
|
||||
}
|
||||
}
|
||||
|
||||
def RemoveItemFromSlotCallback(item : Equipment, slot : Int) : Unit = {
|
||||
val obj = ContainerObject
|
||||
val zone = obj.Zone
|
||||
val events = zone.AvatarEvents
|
||||
item.Faction = PlanetSideEmpire.NEUTRAL
|
||||
events ! AvatarServiceMessage(zone.Id, AvatarAction.ObjectDelete(Service.defaultPlayerGUID, item.GUID))
|
||||
}
|
||||
|
||||
def PutItemInSlotCallback(item : Equipment, slot : Int) : Unit = {
|
||||
val obj = ContainerObject
|
||||
val zone = obj.Zone
|
||||
val events = zone.AvatarEvents
|
||||
val definition = item.Definition
|
||||
events ! AvatarServiceMessage(
|
||||
zone.Id,
|
||||
AvatarAction.SendResponse(
|
||||
Service.defaultPlayerGUID,
|
||||
ObjectCreateDetailedMessage(
|
||||
definition.ObjectId,
|
||||
item.GUID,
|
||||
ObjectCreateMessageParent(obj.GUID, slot),
|
||||
definition.Packet.DetailedConstructorData(item).get
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
def SwapItemCallback(item : Equipment) : Unit = {
|
||||
val obj = ContainerObject
|
||||
val zone = obj.Zone
|
||||
zone.AvatarEvents ! AvatarServiceMessage(zone.Id,
|
||||
AvatarAction.SendResponse(
|
||||
Service.defaultPlayerGUID,
|
||||
ObjectDetachMessage(obj.GUID, item.GUID, Vector3.Zero, 0f)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -595,9 +595,8 @@ class PlayerControl(player : Player) extends Actor
|
|||
def RemoveItemFromSlotCallback(item : Equipment, slot : Int) : Unit = {
|
||||
val obj = ContainerObject
|
||||
val zone = obj.Zone
|
||||
val name = player.Name
|
||||
val toChannel = if(obj.VisibleSlots.contains(slot) || obj.isBackpack) zone.Id else name
|
||||
val events = zone.AvatarEvents
|
||||
val toChannel = if(obj.VisibleSlots.contains(slot)) zone.Id else player.Name
|
||||
item.Faction = PlanetSideEmpire.NEUTRAL
|
||||
if(slot == obj.DrawnSlot) {
|
||||
obj.DrawnSlot = Player.HandsDownSlot
|
||||
|
|
@ -612,55 +611,51 @@ class PlayerControl(player : Player) extends Actor
|
|||
val events = zone.AvatarEvents
|
||||
val name = player.Name
|
||||
val definition = item.Definition
|
||||
val msg = AvatarAction.SendResponse(
|
||||
Service.defaultPlayerGUID,
|
||||
ObjectCreateDetailedMessage(
|
||||
definition.ObjectId,
|
||||
item.GUID,
|
||||
ObjectCreateMessageParent(guid, slot),
|
||||
definition.Packet.DetailedConstructorData(item).get
|
||||
val faction = obj.Faction
|
||||
item.Faction = faction
|
||||
events ! AvatarServiceMessage(
|
||||
name,
|
||||
AvatarAction.SendResponse(
|
||||
Service.defaultPlayerGUID,
|
||||
ObjectCreateDetailedMessage(
|
||||
definition.ObjectId,
|
||||
item.GUID,
|
||||
ObjectCreateMessageParent(guid, slot),
|
||||
definition.Packet.DetailedConstructorData(item).get
|
||||
)
|
||||
)
|
||||
)
|
||||
if(obj.isBackpack) {
|
||||
item.Faction = PlanetSideEmpire.NEUTRAL
|
||||
events ! AvatarServiceMessage(zone.Id, msg)
|
||||
if(obj.VisibleSlots.contains(slot)) {
|
||||
events ! AvatarServiceMessage(zone.Id, AvatarAction.EquipmentInHand(guid, guid, slot, item))
|
||||
}
|
||||
else {
|
||||
val faction = obj.Faction
|
||||
item.Faction = faction
|
||||
events ! AvatarServiceMessage(name, msg)
|
||||
if(obj.VisibleSlots.contains(slot)) {
|
||||
events ! AvatarServiceMessage(zone.Id, AvatarAction.EquipmentInHand(guid, guid, slot, item))
|
||||
}
|
||||
//handle specific types of items
|
||||
item match {
|
||||
case trigger : BoomerTrigger =>
|
||||
//pick up the trigger, own the boomer; make certain whole faction is aware of that
|
||||
(zone.GUID(trigger.Companion), zone.Players.find { _.name == name }) match {
|
||||
case (Some(boomer : BoomerDeployable), Some(avatar))
|
||||
if !boomer.OwnerName.contains(name) || boomer.Faction != faction =>
|
||||
val bguid = boomer.GUID
|
||||
val faction = player.Faction
|
||||
val factionChannel = faction.toString
|
||||
if(avatar.Deployables.Add(boomer)) {
|
||||
boomer.Faction = faction
|
||||
boomer.AssignOwnership(player)
|
||||
avatar.Deployables.UpdateUIElement(boomer.Definition.Item).foreach { case (currElem, curr, maxElem, max) =>
|
||||
events ! AvatarServiceMessage(name, AvatarAction.PlanetsideAttributeToAll(Service.defaultPlayerGUID, maxElem, max))
|
||||
events ! AvatarServiceMessage(name, AvatarAction.PlanetsideAttributeToAll(Service.defaultPlayerGUID, currElem, curr))
|
||||
}
|
||||
zone.LocalEvents ! LocalServiceMessage.Deployables(RemoverActor.ClearSpecific(List(boomer), zone))
|
||||
events ! AvatarServiceMessage(factionChannel, AvatarAction.SetEmpire(Service.defaultPlayerGUID, bguid, faction))
|
||||
zone.LocalEvents ! LocalServiceMessage(factionChannel,
|
||||
LocalAction.DeployableMapIcon(Service.defaultPlayerGUID, DeploymentAction.Build,
|
||||
DeployableInfo(bguid, DeployableIcon.Boomer, boomer.Position, boomer.Owner.getOrElse(PlanetSideGUID(0)))
|
||||
)
|
||||
)
|
||||
//handle specific types of items
|
||||
item match {
|
||||
case trigger : BoomerTrigger =>
|
||||
//pick up the trigger, own the boomer; make certain whole faction is aware of that
|
||||
(zone.GUID(trigger.Companion), zone.Players.find { _.name == name }) match {
|
||||
case (Some(boomer : BoomerDeployable), Some(avatar))
|
||||
if !boomer.OwnerName.contains(name) || boomer.Faction != faction =>
|
||||
val bguid = boomer.GUID
|
||||
val faction = player.Faction
|
||||
val factionChannel = faction.toString
|
||||
if(avatar.Deployables.Add(boomer)) {
|
||||
boomer.Faction = faction
|
||||
boomer.AssignOwnership(player)
|
||||
avatar.Deployables.UpdateUIElement(boomer.Definition.Item).foreach { case (currElem, curr, maxElem, max) =>
|
||||
events ! AvatarServiceMessage(name, AvatarAction.PlanetsideAttributeToAll(Service.defaultPlayerGUID, maxElem, max))
|
||||
events ! AvatarServiceMessage(name, AvatarAction.PlanetsideAttributeToAll(Service.defaultPlayerGUID, currElem, curr))
|
||||
}
|
||||
case _ => ; //pointless trigger?
|
||||
}
|
||||
case _ => ;
|
||||
}
|
||||
zone.LocalEvents ! LocalServiceMessage.Deployables(RemoverActor.ClearSpecific(List(boomer), zone))
|
||||
events ! AvatarServiceMessage(factionChannel, AvatarAction.SetEmpire(Service.defaultPlayerGUID, bguid, faction))
|
||||
zone.LocalEvents ! LocalServiceMessage(factionChannel,
|
||||
LocalAction.DeployableMapIcon(Service.defaultPlayerGUID, DeploymentAction.Build,
|
||||
DeployableInfo(bguid, DeployableIcon.Boomer, boomer.Position, boomer.Owner.getOrElse(PlanetSideGUID(0)))
|
||||
)
|
||||
)
|
||||
}
|
||||
case _ => ; //pointless trigger?
|
||||
}
|
||||
case _ => ;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
package net.psforever.objects.zones
|
||||
|
||||
import akka.actor.{Actor, ActorRef, Props}
|
||||
import net.psforever.objects.avatar.PlayerControl
|
||||
import net.psforever.objects.avatar.{CorpseControl, PlayerControl}
|
||||
import net.psforever.objects.{Avatar, Default, Player}
|
||||
|
||||
import scala.annotation.tailrec
|
||||
|
|
@ -65,22 +65,18 @@ class ZonePopulationActor(zone : Zone, playerMap : TrieMap[Avatar, Option[Player
|
|||
case Zone.Corpse.Add(player) =>
|
||||
//player can be a corpse if they are in the current zone or are not in any zone
|
||||
//player is "found" if their avatar can be matched by name within this zone and it has a character
|
||||
val (canBeCorpse, playerNotFound) = if(player.Zone == zone) {
|
||||
playerMap.find { case (a, _) => a.name == player.Name } match {
|
||||
case Some((a, Some(p))) if p eq player =>
|
||||
PopulationRelease(a, playerMap)
|
||||
(true, false)
|
||||
case Some((a, None)) =>
|
||||
(true, true)
|
||||
case _ =>
|
||||
(false, false)
|
||||
}
|
||||
val (canBeCorpse, control) = playerMap.find { case (a, _) => a.name == player.Name } match {
|
||||
case Some((a, Some(p))) if p eq player =>
|
||||
PopulationRelease(a, playerMap)
|
||||
context.stop(player.Actor)
|
||||
(true, Some(player.Actor))
|
||||
case Some((_, None)) =>
|
||||
(true, None)
|
||||
case _ =>
|
||||
(player.Zone == Zone.Nowhere || player.Zone == zone, None)
|
||||
}
|
||||
else {
|
||||
(player.Zone == Zone.Nowhere, true)
|
||||
}
|
||||
if(canBeCorpse && CorpseAdd(player, corpseList) && playerNotFound) {
|
||||
player.Actor = context.actorOf(Props(classOf[PlayerControl], player), name = s"corpse_of_${GetPlayerControlName(player, None)}")
|
||||
if(canBeCorpse && CorpseAdd(player, corpseList)) {
|
||||
player.Actor = context.actorOf(Props(classOf[CorpseControl], player), name = s"corpse_of_${GetPlayerControlName(player, control)}")
|
||||
player.Zone = zone
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -453,7 +453,7 @@ class ZonePopulationTest extends ActorTest {
|
|||
|
||||
assert(zone.Corpses.isEmpty)
|
||||
zone.Population ! Zone.Corpse.Add(player)
|
||||
expectNoMessage(Duration.create(100, "ms"))
|
||||
expectNoMessage(Duration.create(500, "ms"))
|
||||
assert(zone.Corpses.size == 1)
|
||||
assert(zone.Corpses.head == player)
|
||||
}
|
||||
|
|
@ -466,12 +466,12 @@ class ZonePopulationTest extends ActorTest {
|
|||
zone.Actor ! Zone.Init()
|
||||
expectNoMessage(200 milliseconds)
|
||||
zone.Population ! Zone.Corpse.Add(player)
|
||||
expectNoMessage(Duration.create(100, "ms"))
|
||||
expectNoMessage(Duration.create(500, "ms"))
|
||||
|
||||
assert(zone.Corpses.size == 1)
|
||||
assert(zone.Corpses.head == player)
|
||||
zone.Population ! Zone.Corpse.Remove(player)
|
||||
expectNoMessage(Duration.create(100, "ms"))
|
||||
expectNoMessage(Duration.create(200, "ms"))
|
||||
assert(zone.Corpses.isEmpty)
|
||||
}
|
||||
|
||||
|
|
@ -489,14 +489,14 @@ class ZonePopulationTest extends ActorTest {
|
|||
zone.Population ! Zone.Corpse.Add(player1)
|
||||
zone.Population ! Zone.Corpse.Add(player2)
|
||||
zone.Population ! Zone.Corpse.Add(player3)
|
||||
expectNoMessage(Duration.create(100, "ms"))
|
||||
expectNoMessage(Duration.create(500, "ms"))
|
||||
|
||||
assert(zone.Corpses.size == 3)
|
||||
assert(zone.Corpses.head == player1)
|
||||
assert(zone.Corpses(1) == player2)
|
||||
assert(zone.Corpses(2) == player3)
|
||||
zone.Population ! Zone.Corpse.Remove(player2)
|
||||
expectNoMessage(Duration.create(100, "ms"))
|
||||
expectNoMessage(Duration.create(200, "ms"))
|
||||
assert(zone.Corpses.size == 2)
|
||||
assert(zone.Corpses.head == player1)
|
||||
assert(zone.Corpses(1) == player3)
|
||||
|
|
@ -512,7 +512,7 @@ class ZonePopulationTest extends ActorTest {
|
|||
|
||||
assert(zone.Corpses.isEmpty)
|
||||
zone.Population ! Zone.Corpse.Add(player)
|
||||
expectNoMessage(Duration.create(100, "ms"))
|
||||
expectNoMessage(Duration.create(200, "ms"))
|
||||
assert(zone.Corpses.isEmpty)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue