mirror of
https://github.com/2revoemag/PSF-BotServer.git
synced 2026-07-12 06:55:10 +00:00
Vehicle Gating with Passengers (#1072)
* guarding against match errors in various places; increased frequency of psm array purge; fixed issues with seated passengers after vehicle gating * due to increased frequency of clearing psm data, changed from Array to LongMap
This commit is contained in:
parent
a5a232ffdc
commit
66f45edcd3
13 changed files with 61 additions and 44 deletions
|
|
@ -717,6 +717,7 @@ class ChatActor(
|
||||||
sessionActor ! SessionActor.SendResponse(
|
sessionActor ! SessionActor.SendResponse(
|
||||||
message.copy(messageType = UNK_229, contents = "@CMT_ZONE_usage")
|
message.copy(messageType = UNK_229, contents = "@CMT_ZONE_usage")
|
||||||
)
|
)
|
||||||
|
case _ => ()
|
||||||
}
|
}
|
||||||
|
|
||||||
case (CMT_WARP, _, contents) if gmCommandAllowed =>
|
case (CMT_WARP, _, contents) if gmCommandAllowed =>
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import akka.actor.typed.scaladsl.adapter._
|
||||||
import akka.actor.{ActorContext, typed}
|
import akka.actor.{ActorContext, typed}
|
||||||
import net.psforever.services.Service
|
import net.psforever.services.Service
|
||||||
|
|
||||||
|
import scala.collection.mutable
|
||||||
import scala.concurrent.ExecutionContext.Implicits.global
|
import scala.concurrent.ExecutionContext.Implicits.global
|
||||||
import scala.concurrent.duration._
|
import scala.concurrent.duration._
|
||||||
//
|
//
|
||||||
|
|
@ -32,9 +33,8 @@ class SessionAvatarHandlers(
|
||||||
implicit val context: ActorContext
|
implicit val context: ActorContext
|
||||||
) extends CommonSessionInterfacingFunctionality {
|
) extends CommonSessionInterfacingFunctionality {
|
||||||
//TODO player characters only exist within a certain range of GUIDs for a given zone; this is overkill
|
//TODO player characters only exist within a certain range of GUIDs for a given zone; this is overkill
|
||||||
private[support] var lastSeenStreamMessage: Array[SessionAvatarHandlers.LastUpstream] = {
|
private[support] var lastSeenStreamMessage: mutable.LongMap[SessionAvatarHandlers.LastUpstream] =
|
||||||
SessionAvatarHandlers.blankUpstreamMessages(65535)
|
mutable.LongMap[SessionAvatarHandlers.LastUpstream]()
|
||||||
}
|
|
||||||
private[this] val hidingPlayerRandomizer = new scala.util.Random
|
private[this] val hidingPlayerRandomizer = new scala.util.Random
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -73,8 +73,8 @@ class SessionAvatarHandlers(
|
||||||
canSeeReallyFar
|
canSeeReallyFar
|
||||||
) if isNotSameTarget =>
|
) if isNotSameTarget =>
|
||||||
val pstateToSave = pstate.copy(timestamp = 0)
|
val pstateToSave = pstate.copy(timestamp = 0)
|
||||||
val (lastMsg, lastTime, lastPosition, wasVisible) = lastSeenStreamMessage(guid.guid) match {
|
val (lastMsg, lastTime, lastPosition, wasVisible) = lastSeenStreamMessage.get(guid.guid) match {
|
||||||
case SessionAvatarHandlers.LastUpstream(Some(msg), visible, time) => (Some(msg), time, msg.pos, visible)
|
case Some(SessionAvatarHandlers.LastUpstream(Some(msg), visible, time)) => (Some(msg), time, msg.pos, visible)
|
||||||
case _ => (None, 0L, Vector3.Zero, false)
|
case _ => (None, 0L, Vector3.Zero, false)
|
||||||
}
|
}
|
||||||
val drawConfig = Config.app.game.playerDraw //m
|
val drawConfig = Config.app.game.playerDraw //m
|
||||||
|
|
@ -129,10 +129,10 @@ class SessionAvatarHandlers(
|
||||||
isCloaking
|
isCloaking
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
lastSeenStreamMessage(guid.guid) = SessionAvatarHandlers.LastUpstream(Some(pstateToSave), visible=true, now)
|
lastSeenStreamMessage.put(guid.guid, SessionAvatarHandlers.LastUpstream(Some(pstateToSave), visible=true, now))
|
||||||
} else {
|
} else {
|
||||||
//is visible, but skip reinforcement
|
//is visible, but skip reinforcement
|
||||||
lastSeenStreamMessage(guid.guid) = SessionAvatarHandlers.LastUpstream(Some(pstateToSave), visible=true, lastTime)
|
lastSeenStreamMessage.put(guid.guid, SessionAvatarHandlers.LastUpstream(Some(pstateToSave), visible=true, lastTime))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
//conditions where the target is not currently visible
|
//conditions where the target is not currently visible
|
||||||
|
|
@ -151,10 +151,10 @@ class SessionAvatarHandlers(
|
||||||
is_cloaked = isCloaking
|
is_cloaked = isCloaking
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
lastSeenStreamMessage(guid.guid) = SessionAvatarHandlers.LastUpstream(Some(pstateToSave), visible=false, now)
|
lastSeenStreamMessage.put(guid.guid, SessionAvatarHandlers.LastUpstream(Some(pstateToSave), visible=false, now))
|
||||||
} else {
|
} else {
|
||||||
//skip drawing altogether
|
//skip drawing altogether
|
||||||
lastSeenStreamMessage(guid.guid) = SessionAvatarHandlers.LastUpstream(Some(pstateToSave), visible=false, lastTime)
|
lastSeenStreamMessage.put(guid.guid, SessionAvatarHandlers.LastUpstream(Some(pstateToSave), visible=false, lastTime))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -549,7 +549,7 @@ class SessionAvatarHandlers(
|
||||||
continent.GUID(weaponGuid).collect {
|
continent.GUID(weaponGuid).collect {
|
||||||
case tool: Tool if tool.Magazine == 0 =>
|
case tool: Tool if tool.Magazine == 0 =>
|
||||||
// check that the magazine is still empty before sending WeaponDryFireMessage
|
// check that the magazine is still empty before sending WeaponDryFireMessage
|
||||||
// if it has been reloaded since then, other clients not see it firing
|
// if it has been reloaded since then, other clients will not see it firing
|
||||||
sendResponse(WeaponDryFireMessage(weaponGuid))
|
sendResponse(WeaponDryFireMessage(weaponGuid))
|
||||||
case _ =>
|
case _ =>
|
||||||
sendResponse(WeaponDryFireMessage(weaponGuid))
|
sendResponse(WeaponDryFireMessage(weaponGuid))
|
||||||
|
|
@ -562,8 +562,4 @@ class SessionAvatarHandlers(
|
||||||
|
|
||||||
object SessionAvatarHandlers {
|
object SessionAvatarHandlers {
|
||||||
private[support] case class LastUpstream(msg: Option[AvatarResponse.PlayerState], visible: Boolean, time: Long)
|
private[support] case class LastUpstream(msg: Option[AvatarResponse.PlayerState], visible: Boolean, time: Long)
|
||||||
|
|
||||||
private[support] def blankUpstreamMessages(n: Int): Array[LastUpstream] = {
|
|
||||||
Array.fill[SessionAvatarHandlers.LastUpstream](n)(elem = LastUpstream(None, visible=false, 0L))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -732,18 +732,19 @@ class ZoningOperations(
|
||||||
(manifest.passengers.find {
|
(manifest.passengers.find {
|
||||||
_.name.equals(playerName)
|
_.name.equals(playerName)
|
||||||
} match {
|
} match {
|
||||||
case Some(entry) if vehicle.Seats(entry.mount).occupant.isEmpty =>
|
case Some(entry) if vehicle.Seat(entry.mount).flatMap { _.occupant }.isEmpty =>
|
||||||
player.VehicleSeated = None
|
player.VehicleSeated = None
|
||||||
vehicle.Seats(entry.mount).mount(player)
|
vehicle.Seats(entry.mount).mount(player)
|
||||||
player.VehicleSeated = vehicle.GUID
|
player.VehicleSeated = vehicle.GUID
|
||||||
Some(vehicle)
|
Some((None, Some(vehicle)))
|
||||||
case Some(entry) if vehicle.Seats(entry.mount).occupant.contains(player) =>
|
case Some(entry) if vehicle.Seat(entry.mount).flatMap { _.occupant }.contains(player) =>
|
||||||
Some(vehicle)
|
player.VehicleSeated = vehicle.GUID
|
||||||
|
Some((None, Some(vehicle)))
|
||||||
case Some(entry) =>
|
case Some(entry) =>
|
||||||
log.warn(
|
log.warn(
|
||||||
s"TransferPassenger: $playerName tried to mount seat ${entry.mount} during summoning, but it was already occupied, and ${player.Sex.pronounSubject} was rebuked"
|
s"TransferPassenger: $playerName tried to mount seat ${entry.mount} during summoning, but it was already occupied, and ${player.Sex.pronounSubject} was rebuked"
|
||||||
)
|
)
|
||||||
None
|
Some((None, None))
|
||||||
case None =>
|
case None =>
|
||||||
//log.warn(s"TransferPassenger: $playerName is missing from the manifest of a summoning ${vehicle.Definition.Name} from ${vehicle.Zone.id}")
|
//log.warn(s"TransferPassenger: $playerName is missing from the manifest of a summoning ${vehicle.Definition.Name} from ${vehicle.Zone.id}")
|
||||||
None
|
None
|
||||||
|
|
@ -753,8 +754,8 @@ class ZoningOperations(
|
||||||
} match {
|
} match {
|
||||||
case Some(entry) =>
|
case Some(entry) =>
|
||||||
vehicle.CargoHolds(entry.mount).occupant match {
|
vehicle.CargoHolds(entry.mount).occupant match {
|
||||||
case out@Some(cargo) if cargo.Seats(0).occupants.exists(_.Name.equals(playerName)) =>
|
case out @ Some(cargo) if cargo.Seats(0).occupants.exists(_.Name.equals(playerName)) =>
|
||||||
out
|
Some((Some(vehicle), out))
|
||||||
case _ =>
|
case _ =>
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
@ -762,13 +763,11 @@ class ZoningOperations(
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
} match {
|
} match {
|
||||||
case Some(cargo: Vehicle) =>
|
case Some((Some(ferry), Some(cargo))) =>
|
||||||
galaxyService ! Service.Leave(Some(temp_channel)) //temporary vehicle-specific channel (see above)
|
cargo.MountedIn = ferry.GUID
|
||||||
spawn.deadState = DeadState.Release
|
handleTransferPassengerVehicle(cargo, temp_channel)
|
||||||
sendResponse(AvatarDeadStateMessage(DeadState.Release, 0, 0, player.Position, player.Faction, unk5=true))
|
case Some((None, Some(_: Vehicle))) =>
|
||||||
interstellarFerry = Some(cargo) //on the other continent and registered to that continent's GUID system
|
handleTransferPassengerVehicle(vehicle, temp_channel)
|
||||||
cargo.MountedIn = vehicle.GUID
|
|
||||||
spawn.LoadZonePhysicalSpawnPoint(cargo.Continent, cargo.Position, cargo.Orientation, respawnTime = 1 seconds, None)
|
|
||||||
case _ =>
|
case _ =>
|
||||||
interstellarFerry match {
|
interstellarFerry match {
|
||||||
case None =>
|
case None =>
|
||||||
|
|
@ -779,6 +778,14 @@ class ZoningOperations(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private def handleTransferPassengerVehicle(vehicle: Vehicle, temporaryChannel: String): Unit = {
|
||||||
|
galaxyService ! Service.Leave(Some(temporaryChannel)) //temporary vehicle-specific channel (see above)
|
||||||
|
spawn.deadState = DeadState.Release
|
||||||
|
sendResponse(AvatarDeadStateMessage(DeadState.Release, 0, 0, player.Position, player.Faction, unk5=true))
|
||||||
|
interstellarFerry = Some(vehicle) //on the other continent and registered to that continent's GUID system
|
||||||
|
spawn.LoadZonePhysicalSpawnPoint(vehicle.Continent, vehicle.Position, vehicle.Orientation, respawnTime = 1 seconds, None)
|
||||||
|
}
|
||||||
|
|
||||||
def handleDroppodLaunchDenial(errorCode: DroppodError): Unit = {
|
def handleDroppodLaunchDenial(errorCode: DroppodError): Unit = {
|
||||||
sendResponse(DroppodLaunchResponseMessage(errorCode, player.GUID))
|
sendResponse(DroppodLaunchResponseMessage(errorCode, player.GUID))
|
||||||
}
|
}
|
||||||
|
|
@ -1446,7 +1453,6 @@ class ZoningOperations(
|
||||||
Deployables.Disown(continent, avatar, context.self)
|
Deployables.Disown(continent, avatar, context.self)
|
||||||
spawn.drawDeloyableIcon = spawn.RedrawDeployableIcons //important for when SetCurrentAvatar initializes the UI next zone
|
spawn.drawDeloyableIcon = spawn.RedrawDeployableIcons //important for when SetCurrentAvatar initializes the UI next zone
|
||||||
sessionData.squad.squadSetup = sessionData.squad.ZoneChangeSquadSetup
|
sessionData.squad.squadSetup = sessionData.squad.ZoneChangeSquadSetup
|
||||||
sessionData.avatarResponse.lastSeenStreamMessage = SessionAvatarHandlers.blankUpstreamMessages(65535)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -1923,6 +1929,7 @@ class ZoningOperations(
|
||||||
if (zoningStatus == Zoning.Status.Deconstructing) {
|
if (zoningStatus == Zoning.Status.Deconstructing) {
|
||||||
sessionData.stopDeconstructing()
|
sessionData.stopDeconstructing()
|
||||||
}
|
}
|
||||||
|
sessionData.avatarResponse.lastSeenStreamMessage.clear()
|
||||||
upstreamMessageCount = 0
|
upstreamMessageCount = 0
|
||||||
setAvatar = false
|
setAvatar = false
|
||||||
sessionData.persist()
|
sessionData.persist()
|
||||||
|
|
@ -1956,6 +1963,7 @@ class ZoningOperations(
|
||||||
if (zoningStatus == Zoning.Status.Deconstructing) {
|
if (zoningStatus == Zoning.Status.Deconstructing) {
|
||||||
sessionData.stopDeconstructing()
|
sessionData.stopDeconstructing()
|
||||||
}
|
}
|
||||||
|
sessionData.avatarResponse.lastSeenStreamMessage.clear()
|
||||||
upstreamMessageCount = 0
|
upstreamMessageCount = 0
|
||||||
setAvatar = false
|
setAvatar = false
|
||||||
sessionData.persist()
|
sessionData.persist()
|
||||||
|
|
|
||||||
|
|
@ -804,8 +804,8 @@ object WorldSession {
|
||||||
val name = definition.Name
|
val name = definition.Name
|
||||||
GlobalDefinitions.isGrenade(definition) && (name.contains("frag") || name.contains("plasma"))
|
GlobalDefinitions.isGrenade(definition) && (name.contains("frag") || name.contains("plasma"))
|
||||||
} match {
|
} match {
|
||||||
case Some(InventoryItem(equipment, slotNum)) =>Some(equipment.asInstanceOf[Tool], slotNum)
|
case Some(InventoryItem(equipment, slotNum)) => Some(equipment.asInstanceOf[Tool], slotNum)
|
||||||
case None => None
|
case _ => None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -86,7 +86,7 @@ class GridInventory extends Container {
|
||||||
items.values.find({ case InventoryItem(obj, _) => obj.HasGUID && obj.GUID == guid }) match {
|
items.values.find({ case InventoryItem(obj, _) => obj.HasGUID && obj.GUID == guid }) match {
|
||||||
case Some(InventoryItem(_, index)) =>
|
case Some(InventoryItem(_, index)) =>
|
||||||
Some(index)
|
Some(index)
|
||||||
case None =>
|
case _ =>
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -69,7 +69,7 @@ trait SectorTraits {
|
||||||
* @param eqFunc a custom equivalence function to distinguish between the entities in the list
|
* @param eqFunc a custom equivalence function to distinguish between the entities in the list
|
||||||
* @tparam A the type of object that will be the entities stored in the list
|
* @tparam A the type of object that will be the entities stored in the list
|
||||||
*/
|
*/
|
||||||
class SectorListOf[A](eqFunc: (A, A) => Boolean = (a: A, b: A) => a equals b) {
|
class SectorListOf[A](eqFunc: (A, A) => Boolean = (a: A, b: A) => a == b) {
|
||||||
private val internalList: ListBuffer[A] = ListBuffer[A]()
|
private val internalList: ListBuffer[A] = ListBuffer[A]()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -59,6 +59,7 @@ object LoginMessage extends Marshallable[LoginMessage] {
|
||||||
a match {
|
a match {
|
||||||
case username :: Some(password) :: None :: HNil => Left(username :: password :: HNil)
|
case username :: Some(password) :: None :: HNil => Left(username :: password :: HNil)
|
||||||
case username :: None :: Some(token) :: HNil => Right(token :: username :: HNil)
|
case username :: None :: Some(token) :: HNil => Right(token :: username :: HNil)
|
||||||
|
case username :: _ :: _ :: HNil => Right(username :: "" :: HNil) //this will fail
|
||||||
}
|
}
|
||||||
|
|
||||||
either(bool, passwordPath, tokenPath).xmap[Struct](from, to)
|
either(bool, passwordPath, tokenPath).xmap[Struct](from, to)
|
||||||
|
|
|
||||||
|
|
@ -166,6 +166,9 @@ object PropertyOverrideMessage extends Marshallable[PropertyOverrideMessage] {
|
||||||
|
|
||||||
case target :: _ :: Some(first) :: Some(other) :: HNil =>
|
case target :: _ :: Some(first) :: Some(other) :: HNil =>
|
||||||
GamePropertyTarget(target, first +: other)
|
GamePropertyTarget(target, first +: other)
|
||||||
|
|
||||||
|
case target :: _ :: _ :: Some(other) :: HNil =>
|
||||||
|
GamePropertyTarget(target, other)
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
case GamePropertyTarget(target, list) =>
|
case GamePropertyTarget(target, list) =>
|
||||||
|
|
@ -202,6 +205,9 @@ object PropertyOverrideMessage extends Marshallable[PropertyOverrideMessage] {
|
||||||
|
|
||||||
case zone :: _ :: Some(first) :: Some(other) :: HNil =>
|
case zone :: _ :: Some(first) :: Some(other) :: HNil =>
|
||||||
GamePropertyScope(zone, first +: other)
|
GamePropertyScope(zone, first +: other)
|
||||||
|
|
||||||
|
case zone :: _ :: None :: Some(other) :: HNil =>
|
||||||
|
GamePropertyScope(zone, other)
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
case GamePropertyScope(zone, list) =>
|
case GamePropertyScope(zone, list) =>
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,7 @@ object InventoryData {
|
||||||
}
|
}
|
||||||
).xmap[InventoryData](
|
).xmap[InventoryData](
|
||||||
{
|
{
|
||||||
case _ :: 0 :: c :: HNil =>
|
case _ :: _ :: c :: HNil =>
|
||||||
InventoryData(c)
|
InventoryData(c)
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ object LittleBuddyProjectileData extends Marshallable[LittleBuddyProjectileData]
|
||||||
("unk4" | bool)
|
("unk4" | bool)
|
||||||
).exmap[LittleBuddyProjectileData](
|
).exmap[LittleBuddyProjectileData](
|
||||||
{
|
{
|
||||||
case data :: u2 :: 31 :: u4 :: HNil =>
|
case data :: u2 :: _ :: u4 :: HNil =>
|
||||||
Attempt.successful(LittleBuddyProjectileData(data, u2, u4))
|
Attempt.successful(LittleBuddyProjectileData(data, u2, u4))
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -3,10 +3,10 @@ package net.psforever.packet.game.objectcreate
|
||||||
|
|
||||||
import net.psforever.packet.PacketHelpers
|
import net.psforever.packet.PacketHelpers
|
||||||
import net.psforever.types.PlanetSideGUID
|
import net.psforever.types.PlanetSideGUID
|
||||||
import scodec.Attempt.Successful
|
import scodec.Attempt.{Failure, Successful}
|
||||||
import scodec.Codec
|
import scodec.{Codec, Err}
|
||||||
import scodec.codecs._
|
import scodec.codecs._
|
||||||
import shapeless.HNil //note: do not import shapeless.:: at top level; it messes up List's :: functionality
|
import shapeless.HNil
|
||||||
|
|
||||||
import scala.collection.mutable.ListBuffer
|
import scala.collection.mutable.ListBuffer
|
||||||
|
|
||||||
|
|
@ -222,6 +222,9 @@ object MountableInventory {
|
||||||
|
|
||||||
case _ :: slot :: Some(next) :: HNil =>
|
case _ :: slot :: Some(next) :: HNil =>
|
||||||
Successful(Some(InventorySeat(slot, next)))
|
Successful(Some(InventorySeat(slot, next)))
|
||||||
|
|
||||||
|
case _ =>
|
||||||
|
Failure(Err("bad seat decoding"))
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
case None =>
|
case None =>
|
||||||
|
|
|
||||||
|
|
@ -147,7 +147,7 @@ object ObjectCreateBase {
|
||||||
cls :: guid :: None :: HNil
|
cls :: guid :: None :: HNil
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
case cls :: guid :: None :: HNil =>
|
case cls :: guid :: _ :: HNil =>
|
||||||
cls :: guid :: HNil
|
cls :: guid :: HNil
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
@ -157,17 +157,19 @@ object ObjectCreateBase {
|
||||||
*/
|
*/
|
||||||
private val parent: Codec[parentPattern] = (
|
private val parent: Codec[parentPattern] = (
|
||||||
("parentGuid" | PlanetSideGUID.codec) :: //16u
|
("parentGuid" | PlanetSideGUID.codec) :: //16u
|
||||||
("objectClass" | uintL(0xb)) :: //11u
|
("objectClass" | uintL(0xb)) :: //11u
|
||||||
("guid" | PlanetSideGUID.codec) :: //16u
|
("guid" | PlanetSideGUID.codec) :: //16u
|
||||||
("parentSlotIndex" | PacketHelpers.encodedStringSize) //8u or 16u
|
("parentSlotIndex" | PacketHelpers.encodedStringSize) //8u or 16u
|
||||||
).xmap[parentPattern](
|
).exmap[parentPattern](
|
||||||
{
|
{
|
||||||
case pguid :: cls :: guid :: slot :: HNil =>
|
case pguid :: cls :: guid :: slot :: HNil =>
|
||||||
cls :: guid :: Some(ObjectCreateMessageParent(pguid, slot)) :: HNil
|
Attempt.Successful(cls :: guid :: Some(ObjectCreateMessageParent(pguid, slot)) :: HNil)
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
case cls :: guid :: Some(ObjectCreateMessageParent(pguid, slot)) :: HNil =>
|
case cls :: guid :: Some(ObjectCreateMessageParent(pguid, slot)) :: HNil =>
|
||||||
pguid :: cls :: guid :: slot :: HNil
|
Attempt.Successful(pguid :: cls :: guid :: slot :: HNil)
|
||||||
|
case _ =>
|
||||||
|
Attempt.Failure(Err("expecting parent data, but found none"))
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -642,7 +642,7 @@ class SquadService extends Actor {
|
||||||
val squad = features.Squad
|
val squad = features.Squad
|
||||||
LeaveSquad(squad.Membership(position).CharId, features)
|
LeaveSquad(squad.Membership(position).CharId, features)
|
||||||
out
|
out
|
||||||
case None =>
|
case _ =>
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
case FindLfsSoldiersForRole(_) =>
|
case FindLfsSoldiersForRole(_) =>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue