a little over-zealous message bundling

This commit is contained in:
Fate-JH 2026-06-08 19:49:05 -04:00
parent 1507b91f5e
commit 9d2d1cae9f
27 changed files with 485 additions and 488 deletions

View file

@ -17,7 +17,7 @@ import net.psforever.objects.zones.Zone
import net.psforever.packet.game.{ChatMsg, SetChatFilterMessage}
import net.psforever.services.Service
import net.psforever.services.avatar.AvatarAction
import net.psforever.services.base.envelope.MessageEnvelope
import net.psforever.services.base.envelope.{BundledEnvelope, MessageEnvelope}
import net.psforever.services.base.message.{ObjectDelete, SetEmpire}
import net.psforever.services.chat.{ChatChannel, DefaultChannel, SpectatorChannel, SquadChannel}
import net.psforever.types.ChatMessageType.{CMT_TOGGLESPECTATORMODE, CMT_TOGGLE_GM}
@ -314,18 +314,20 @@ class ChatLogic(val ops: ChatOperations, implicit val context: ActorContext) ext
val events = continent.AvatarEvents
seeSpectatorsIn = Some(continent)
events ! Service.Join(s"spectator")
continent
.AllPlayers
.filter(_.spectator)
.foreach { spectator =>
val guid = spectator.GUID
val definition = spectator.Definition
events ! MessageEnvelope(
channel,
guid,
AvatarAction.LoadPlayer(definition.ObjectId, guid, definition.Packet.ConstructorData(spectator).get, None)
)
}
events ! BundledEnvelope(
continent
.AllPlayers
.filter(_.spectator)
.map { spectator =>
val guid = spectator.GUID
val definition = spectator.Definition
MessageEnvelope(
channel,
guid,
AvatarAction.LoadPlayer(definition.ObjectId, guid, definition.Packet.ConstructorData(spectator).get, None)
)
}
)
true
}
@ -334,13 +336,15 @@ class ChatLogic(val ops: ChatOperations, implicit val context: ActorContext) ext
val events = continent.AvatarEvents
seeSpectatorsIn = None
events ! Service.Leave("spectator")
continent
.AllPlayers
.filter(_.spectator)
.foreach { spectator =>
val guid = spectator.GUID
events ! MessageEnvelope(channel, guid, ObjectDelete(guid))
}
events ! BundledEnvelope(
continent
.AllPlayers
.filter(_.spectator)
.map { spectator =>
val guid = spectator.GUID
MessageEnvelope(channel, guid, ObjectDelete(guid))
}
)
true
}

View file

@ -14,7 +14,7 @@ import net.psforever.objects.serverobject.turret.{FacilityTurret, WeaponTurret}
import net.psforever.objects.vehicles.AccessPermissionGroup
import net.psforever.objects.vital.InGameHistory
import net.psforever.packet.game.{ChatMsg, DelayedPathMountMsg, DismountVehicleCargoMsg, DismountVehicleMsg, GenericObjectActionMessage, MountVehicleCargoMsg, MountVehicleMsg, ObjectDetachMessage, PlanetsideAttributeMessage, PlayerStasisMessage, PlayerStateShiftMessage, ShiftState}
import net.psforever.services.base.envelope.MessageEnvelope
import net.psforever.services.base.envelope.{BundledEnvelope, MessageEnvelope}
import net.psforever.services.base.message.{SendResponse, SetEmpire}
import net.psforever.services.vehicle.VehicleAction
import net.psforever.types.{BailType, ChatMessageType, DriveState, PlanetSideGUID, Vector3}
@ -212,22 +212,20 @@ class MountHandlerLogic(val ops: SessionMountHandlers, implicit val context: Act
ops.DismountAction(tplayer, obj, seatNum)
continent.actor ! ZoneActor.RemoveFromBlockMap(player) //character doesn't need it
//DismountAction(...) uses vehicle service, so use that service to coordinate the remainder of the messages
events ! MessageEnvelope(
player.Name,
SendResponse(PlayerStasisMessage(pguid)) //the stasis message
)
//when the player dismounts, they will be positioned where the shuttle was when it disappeared in the sky
//the player will fall to the ground and is perfectly vulnerable in this state
//additionally, our player must exist in the current zone
//having no in-game avatar target will throw us out of the map screen when deploying and cause softlock
events ! MessageEnvelope(
player.Name,
SendResponse(PlayerStateShiftMessage(ShiftState(unk=0, obj.Position, obj.Orientation.z, vel=None)))
)
events ! MessageEnvelope(
continent.id,
pguid,
SendResponse(GenericObjectActionMessage(pguid, code=9)) //conceal the player
events ! BundledEnvelope(
MessageEnvelope(player.Name,
SendResponse(Seq(
PlayerStasisMessage(pguid),
PlayerStateShiftMessage(ShiftState(unk=0, obj.Position, obj.Orientation.z, vel=None))
))
),
MessageEnvelope(continent.id, pguid,
SendResponse(GenericObjectActionMessage(pguid, code=9)) /* conceal the player */
)
)
sessionLogic.keepAliveFunc = sessionLogic.zoning.NormalKeepAlive

View file

@ -14,7 +14,7 @@ import net.psforever.objects.vital.RevivingActivity
import net.psforever.objects.vital.interaction.Adversarial
import net.psforever.packet.game.{AvatarImplantMessage, CreateShortcutMessage, ImplantAction, PlanetsideStringAttributeMessage}
import net.psforever.services.avatar.AvatarAction
import net.psforever.services.base.envelope.MessageEnvelope
import net.psforever.services.base.envelope.{BundledEnvelope, MessageEnvelope}
import net.psforever.services.base.message.{ChangeAmmo, ChangeFireState_Start, ChangeFireState_Stop, ObjectDelete, PlanetsideAttribute, ReloadTool, WeaponDryFire}
import net.psforever.types.ImplantType
@ -635,11 +635,12 @@ class AvatarHandlerLogic(val ops: SessionAvatarHandlers, implicit val context: A
}
def killedWhileMounted(obj: PlanetSideGameObject with Mountable, playerGuid: PlanetSideGUID): Unit = {
val events = continent.AvatarEvents
ops.killedWhileMounted(obj, playerGuid)
//make player invisible on client
events ! MessageEnvelope(player.Name, PlanetsideAttribute(playerGuid, 29, 1))
//only the dead player should "see" their own body, so that the death camera has something to focus on
events ! MessageEnvelope(continent.id, playerGuid, ObjectDelete(playerGuid))
continent.AvatarEvents ! BundledEnvelope(
/* make player invisible on client */
MessageEnvelope(player.Name, PlanetsideAttribute(playerGuid, 29, 1)),
/* only the dead player should "see" their own body, so that the death camera has something to focus on */
MessageEnvelope(continent.id, playerGuid, ObjectDelete(playerGuid))
)
}
}

View file

@ -16,7 +16,7 @@ import net.psforever.objects.serverobject.turret.{FacilityTurret, WeaponTurret}
import net.psforever.objects.vehicles.AccessPermissionGroup
import net.psforever.objects.vital.InGameHistory
import net.psforever.packet.game.{ChatMsg, DelayedPathMountMsg, DismountVehicleCargoMsg, DismountVehicleMsg, GenericObjectActionMessage, MountVehicleCargoMsg, MountVehicleMsg, ObjectDetachMessage, PlanetsideAttributeMessage, PlayerStasisMessage, PlayerStateShiftMessage, ShiftState}
import net.psforever.services.base.envelope.MessageEnvelope
import net.psforever.services.base.envelope.{BundledEnvelope, MessageEnvelope}
import net.psforever.services.base.message.{SendResponse, SetEmpire}
import net.psforever.services.vehicle.VehicleAction
import net.psforever.types.{BailType, ChatMessageType, DriveState, PlanetSideGUID, Vector3}
@ -253,14 +253,16 @@ class MountHandlerLogic(val ops: SessionMountHandlers, implicit val context: Act
//the player will fall to the ground and is perfectly vulnerable in this state
//additionally, our player must exist in the current zone
//having no in-game avatar target will throw us out of the map screen when deploying and cause softlock
events ! MessageEnvelope(player.Name, SendResponse(Seq(
PlayerStasisMessage(pguid),
PlayerStateShiftMessage(ShiftState(unk=0, obj.Position, obj.Orientation.z, vel=None))
)))
events ! MessageEnvelope(
continent.id,
pguid,
SendResponse(GenericObjectActionMessage(pguid, code=9)) //conceal the player
events ! BundledEnvelope(
MessageEnvelope(player.Name,
SendResponse(Seq(
PlayerStasisMessage(pguid),
PlayerStateShiftMessage(ShiftState(unk=0, obj.Position, obj.Orientation.z, vel=None))
))
),
MessageEnvelope(continent.id, pguid,
SendResponse(GenericObjectActionMessage(pguid, code=9)) /* conceal the player */
)
)
sessionLogic.keepAliveFunc = sessionLogic.zoning.NormalKeepAlive

View file

@ -12,7 +12,7 @@ import net.psforever.objects.serverobject.mount.Mountable
import net.psforever.objects.serverobject.terminals.implant.ImplantTerminalMech
import net.psforever.objects.vital.InGameHistory
import net.psforever.packet.game.{DelayedPathMountMsg, DismountVehicleCargoMsg, DismountVehicleMsg, GenericObjectActionMessage, MountVehicleCargoMsg, MountVehicleMsg, ObjectDetachMessage, PlayerStasisMessage, PlayerStateShiftMessage, ShiftState}
import net.psforever.services.base.envelope.MessageEnvelope
import net.psforever.services.base.envelope.{BundledEnvelope, MessageEnvelope}
import net.psforever.services.base.message.SendResponse
import net.psforever.services.vehicle.VehicleAction
@ -80,14 +80,16 @@ class MountHandlerLogic(val ops: SessionMountHandlers, implicit val context: Act
//the player will fall to the ground and is perfectly vulnerable in this state
//additionally, our player must exist in the current zone
//having no in-game avatar target will throw us out of the map screen when deploying and cause softlock
events ! MessageEnvelope(player.Name, SendResponse(Seq(
PlayerStasisMessage(pguid),
PlayerStateShiftMessage(ShiftState(unk=0, obj.Position, obj.Orientation.z, vel=None))
)))
events ! MessageEnvelope(
continent.id,
pguid,
SendResponse(GenericObjectActionMessage(pguid, code=9)) //conceal the player
events ! BundledEnvelope(
MessageEnvelope(player.Name,
SendResponse(Seq(
PlayerStasisMessage(pguid),
PlayerStateShiftMessage(ShiftState(unk=0, obj.Position, obj.Orientation.z, vel=None))
))
),
MessageEnvelope(continent.id, pguid,
SendResponse(GenericObjectActionMessage(pguid, code=9)) /* conceal the player */
)
)
context.self ! SessionActor.SetMode(NormalMode)
sessionLogic.keepAliveFunc = sessionLogic.zoning.NormalKeepAlive

View file

@ -18,7 +18,7 @@ import net.psforever.objects.vehicles.Utility.InternalTelepad
import net.psforever.objects.zones.blockmap.BlockMapEntity
import net.psforever.objects.zones.exp.ToDatabase
import net.psforever.services.avatar.support.GroundEnvelope
import net.psforever.services.base.envelope.MessageEnvelope
import net.psforever.services.base.envelope.{BundledEnvelope, MessageEnvelope}
import net.psforever.services.base.message.{ObjectDelete, PlanetsideAttribute, SendResponse}
import net.psforever.services.base.support.RemoverActor
import net.psforever.services.local.support.{CaptureEnvelope, HackCaptureActor}
@ -201,26 +201,26 @@ class GeneralOperations(
val guid = player.GUID
val zone = player.Zone
val events = zone.LocalEvents
val msg = SendResponse(pkt)
sessionLogic
.localSector
.livePlayerList
.filter(_.GUID != guid)
.foreach { p =>
events ! MessageEnvelope(p.Name, msg)
}
//todo better way to collect csr players while utilizing the aforementioned benefit of localSector
val position = player.Position
val rangeSq = {
val range = math.sqrt(2 * math.pow(sessionLogic.localSector.rangeX.toDouble, 2))
range * range
}
zone
val msg = SendResponse(pkt)
val (localRecipients, localRecipientMessages) = sessionLogic
.localSector
.livePlayerList
.filter(_.GUID != guid)
.map { p => (p.Name, MessageEnvelope(p.Name, msg)) }
.unzip
val otherRecipientMessages = zone
.AllPlayers
.filter { p => !p.allowInteraction && p.GUID != guid && Vector3.DistanceSquared(p.Position, position) < rangeSq }
.foreach { p =>
events ! MessageEnvelope(p.Name, msg)
.filter { p =>
!p.allowInteraction && p.GUID != guid && !localRecipients.contains(p.Name) && Vector3.DistanceSquared(p.Position, position) < rangeSq
}
.map(p => MessageEnvelope(p.Name, msg))
events ! BundledEnvelope(localRecipientMessages ++ otherRecipientMessages)
}
def handleDropItem(pkt: DropItemMessage): GeneralOperations.ItemDropState.Behavior = {
@ -1476,23 +1476,21 @@ class GeneralOperations(
val events = continent.AvatarEvents
val zoneid = continent.id
val destinationPosition = dest.Position
events ! MessageEnvelope(zoneid, pguid, ObjectDelete(pguid))
events ! MessageEnvelope(player.Name,
SendResponse(PlayerStateShiftMessage(ShiftState(0, destinationPosition, player.Orientation.z)))
)
player.Position = destinationPosition
events ! MessageEnvelope(zoneid, pguid, AvatarAction.LoadPlayer(
player.Definition.ObjectId,
pguid,
player.Definition.Packet.ConstructorData(player).get,
None
))
useRouterTelepadEffect(pguid, sguid, dguid)
events ! MessageEnvelope(
continent.id,
pguid,
LocalAction.RouterTelepadTransport(pguid, sguid, dguid)
events ! BundledEnvelope(
MessageEnvelope(zoneid, pguid, ObjectDelete(pguid)),
MessageEnvelope(player.Name,
SendResponse(PlayerStateShiftMessage(ShiftState(0, destinationPosition, player.Orientation.z)))
),
MessageEnvelope(zoneid, pguid, AvatarAction.LoadPlayer(
player.Definition.ObjectId,
pguid,
player.Definition.Packet.ConstructorData(player).get,
None
)),
MessageEnvelope(zoneid, pguid, LocalAction.RouterTelepadTransport(pguid, sguid, dguid))
)
useRouterTelepadEffect(pguid, sguid, dguid)
sessionLogic.zoning.spawn.ShiftPosition = destinationPosition
player.LogActivity(TelepadUseActivity(VehicleSource(router), DeployableSource(remoteTelepad), PlayerSource(player)))
} else {

View file

@ -9,8 +9,8 @@ import net.psforever.packet.game.OutfitEventAction.{Initial, Leaving, OutfitInfo
import net.psforever.packet.game.OutfitMembershipResponse.PacketType.CreateResponse
import net.psforever.packet.game._
import net.psforever.services.avatar.AvatarAction
import net.psforever.services.base.envelope.MessageEnvelope
import net.psforever.services.base.message.PlanetsideAttribute
import net.psforever.services.base.envelope.{BundledEnvelope, MessageEnvelope}
import net.psforever.services.base.message.{PlanetsideAttribute, SendResponse}
import net.psforever.services.chat.OutfitChannel
import net.psforever.types.ChatMessageType
import net.psforever.util.Config
@ -50,63 +50,62 @@ object SessionOutfitHandlers {
import scala.concurrent.Future
def HandleOutfitForm(outfitName: String, player: Player, session: SessionData): Unit = {
val zone = player.Zone
val zoneid = zone.id
val charid = player.CharId
val pname = player.Name
val cleanedName = sanitizeOutfitName(outfitName)
cleanedName match {
case Some(validName) =>
ctx.run(findOutfitByName(validName)).flatMap {
case existing if existing.nonEmpty =>
PlayerControl.sendResponse(player.Zone, player.Name,
ChatMsg(ChatMessageType.UNK_227, "@OutfitErrorNameAlreadyTaken"))
PlayerControl.sendResponse(zone, pname,
ChatMsg(ChatMessageType.UNK_227, "@OutfitErrorNameAlreadyTaken")
)
Future.successful(())
case _ =>
createNewOutfit(validName, player.Faction.id, player.CharId).map { outfit =>
val seconds: Long =
outfit.created.atZone(ZoneId.systemDefault()).toInstant.toEpochMilli / 1000
PlayerControl.sendResponse(player.Zone, player.Name,
OutfitEvent(outfit.id, Update(
OutfitInfo(
outfit.name, 0, 0, 1,
OutfitRankNames("", "", "", "", "", "", "", ""),
"",
14, unk11 = true, 0, seconds, 0, 0, 0))))
PlayerControl.sendResponse(player.Zone, player.Name,
OutfitMemberUpdate(outfit.id, player.CharId, 7, flag = true))
PlayerControl.sendResponse(player.Zone, player.Name,
ChatMsg(ChatMessageType.UNK_227, "@OutfitCreateSuccess"))
PlayerControl.sendResponse(player.Zone, player.Name,
OutfitMembershipResponse(CreateResponse, 0, 0, player.CharId, 0, "", "", flag = true))
player.outfit_id = outfit.id
player.outfit_name = outfit.name
player.Zone.AvatarEvents ! MessageEnvelope(
player.Zone.id,
PlanetsideAttribute(player.GUID, 39, outfit.id)
createNewOutfit(validName, player.Faction.id, charid).map { outfit =>
val outfitId = outfit.id
val outfitName = outfit.name
val seconds: Long = outfit.created.atZone(ZoneId.systemDefault()).toInstant.toEpochMilli / 1000
player.outfit_id = outfitId
player.outfit_name = outfitName
zone.AvatarEvents ! BundledEnvelope(
MessageEnvelope(pname, SendResponse(List(
OutfitEvent(outfitId, Update(
OutfitInfo(
outfitName, 0, 0, 1,
OutfitRankNames("", "", "", "", "", "", "", ""),
"",
14, unk11 = true, 0, seconds, 0, 0, 0)
)),
OutfitMemberUpdate(outfitId, charid, 7, flag = true),
ChatMsg(ChatMessageType.UNK_227, "@OutfitCreateSuccess"),
OutfitMembershipResponse(CreateResponse, 0, 0, charid, 0, "", "", flag = true),
))),
MessageEnvelope(
zoneid,
PlanetsideAttribute(player.GUID, 39, outfitId)
),
MessageEnvelope(
zoneid,
player.GUID,
AvatarAction.PlanetsideStringAttribute(0, outfitName)
)
)
player.Zone.AvatarEvents ! MessageEnvelope(
player.Zone.id,
player.GUID,
AvatarAction.PlanetsideStringAttribute(0, outfit.name)
)
session.chat.JoinChannel(OutfitChannel(player.outfit_id))
session.chat.JoinChannel(OutfitChannel(outfitId))
}
.recover { case e =>
e.printStackTrace()
PlayerControl.sendResponse(player.Zone, player.Name,
ChatMsg(ChatMessageType.UNK_227, "@OutfitCreateFailure"))
PlayerControl.sendResponse(zone, pname,
ChatMsg(ChatMessageType.UNK_227, "@OutfitCreateFailure")
)
}
}
case None =>
PlayerControl.sendResponse(player.Zone, player.Name,
ChatMsg(ChatMessageType.UNK_227, "@OutfitCreateFailure"))
PlayerControl.sendResponse(zone, pname, ChatMsg(ChatMessageType.UNK_227, "@OutfitCreateFailure"))
}
}
@ -127,74 +126,80 @@ object SessionOutfitHandlers {
}
def HandleOutfitInviteAccept(invited: Player, session: SessionData): Unit = {
OutfitInviteManager.getOutfitInvite(invited.CharId) match {
val toName = invited.Name
val toCharId = invited.CharId
val toZone = invited.Zone
val toZoneId = toZone.id
val toGuid = invited.GUID
OutfitInviteManager.getOutfitInvite(toCharId) match {
case Some(outfitInvite) =>
val fromName = outfitInvite.sentFrom.Name
val fromCharId = outfitInvite.sentFrom.CharId
val fromZone = outfitInvite.sentFrom.Zone
val outfitId = outfitInvite.sentFrom.outfit_id
(for {
_ <- addMemberToOutfit(outfitId, invited.CharId)
_ <- addMemberToOutfit(outfitId, toCharId)
outfitOpt <- ctx.run(getOutfitById(outfitId)).map(_.headOption)
memberCount <- ctx.run(getOutfitMemberCount(outfitId))
points <- ctx.run(getOutfitPoints(outfitId)).map(_.headOption.map(_.points).getOrElse(0L))
} yield (outfitOpt, memberCount, points))
.map {
case (Some(outfit), memberCount, points) =>
PlayerControl.sendResponse(outfitInvite.sentFrom.Zone, outfitInvite.sentFrom.Name,
OutfitMembershipResponse(
OutfitMembershipResponse.PacketType.InviteAccepted, 0, 0,
invited.CharId, outfitInvite.sentFrom.CharId, invited.Name, outfit.name, flag = false))
PlayerControl.sendResponse(invited.Zone, invited.Name,
OutfitMembershipResponse(
OutfitMembershipResponse.PacketType.InviteAccepted, 0, 0,
invited.CharId, outfitInvite.sentFrom.CharId, invited.Name, outfit.name, flag = true))
PlayerControl.sendResponse(outfitInvite.sentFrom.Zone, outfitInvite.sentFrom.Name,
OutfitEvent(outfitId, UpdateMemberCount(memberCount)))
PlayerControl.sendResponse(outfitInvite.sentFrom.Zone, outfitInvite.sentFrom.Name,
OutfitMemberEvent(outfitId, invited.CharId,
OutfitMemberEventAction.Update(invited.Name, 0, 0, 0,
OutfitMemberEventAction.PacketType.Padding, 0)))
val outfitName = outfit.name
val seconds: Long = outfit.created.atZone(ZoneId.systemDefault()).toInstant.toEpochMilli / 1000
PlayerControl.sendResponse(invited.Zone, invited.Name,
OutfitEvent(outfitId, Initial(OutfitInfo(
outfit.name, points, points, memberCount,
OutfitRankNames("", "", "", "", "", "", "", ""),
outfit.motd.getOrElse(""),
14, unk11 = true, 0, seconds, 0, 0, 0))))
PlayerControl.sendResponse(invited.Zone, invited.Name,
OutfitMemberUpdate(outfit.id, invited.CharId, 0, flag=true))
OutfitInviteManager.removeOutfitInvite(invited.CharId)
session.chat.JoinChannel(OutfitChannel(outfit.id))
invited.outfit_id = outfit.id
invited.outfit_name = outfit.name
invited.Zone.AvatarEvents ! MessageEnvelope(
invited.Zone.id,
PlanetsideAttribute(invited.GUID, 39, outfit.id)
fromZone.AvatarEvents ! BundledEnvelope(
MessageEnvelope(fromName, SendResponse(List(
OutfitMembershipResponse(
OutfitMembershipResponse.PacketType.InviteAccepted, 0, 0,
toCharId, fromCharId, toName, outfitName, flag = false
),
OutfitEvent(outfitId, UpdateMemberCount(memberCount)),
OutfitMemberEvent(outfitId, toCharId,
OutfitMemberEventAction.Update(toName, 0, 0, 0,
OutfitMemberEventAction.PacketType.Padding, 0
)
)
)))
)
invited.Zone.AvatarEvents ! MessageEnvelope(
invited.Zone.id,
invited.GUID,
AvatarAction.PlanetsideStringAttribute(0, outfit.name)
toZone.AvatarEvents ! BundledEnvelope(
MessageEnvelope(toName, SendResponse(List(
OutfitMembershipResponse(
OutfitMembershipResponse.PacketType.InviteAccepted, 0, 0,
toCharId, fromCharId, toName, outfitName, flag = true
),
OutfitEvent(outfitId, Initial(OutfitInfo(
outfitName, points, points, memberCount,
OutfitRankNames("", "", "", "", "", "", "", ""),
outfit.motd.getOrElse(""),
14, unk11 = true, 0, seconds, 0, 0, 0
))),
OutfitMemberUpdate(outfitId, toCharId, 0, flag=true)
))),
MessageEnvelope(
toZoneId,
PlanetsideAttribute(toGuid, 39, outfitId)
),
MessageEnvelope(
toZoneId,
toGuid,
AvatarAction.PlanetsideStringAttribute(0, outfitName)
)
)
OutfitInviteManager.removeOutfitInvite(toCharId)
session.chat.JoinChannel(OutfitChannel(outfitId))
invited.outfit_id = outfitId
invited.outfit_name = outfitName
case (None, _, _) => ()
PlayerControl.sendResponse(toZone, toName,
ChatMsg(ChatMessageType.UNK_227, "Failed to join outfit")
)
case (None, _, _) =>
PlayerControl.sendResponse(invited.Zone, invited.Name,
ChatMsg(ChatMessageType.UNK_227, "Failed to join outfit"))
}
.recover { case _ =>
PlayerControl.sendResponse(invited.Zone, invited.Name,
ChatMsg(ChatMessageType.UNK_227, "Failed to join outfit"))
}
case None =>
.recover { case _ =>
PlayerControl.sendResponse(toZone, toName,
ChatMsg(ChatMessageType.UNK_227, "Failed to join outfit")
)
}
case None => ()
}
}
@ -218,82 +223,76 @@ object SessionOutfitHandlers {
}
def HandleOutfitKick(zones: Seq[Zone], kickedId: Long, kickedBy: Player, session: SessionData): Unit = {
val outfit_id = kickedBy.outfit_id
// if same id, player has left the outfit by their own choice
if (kickedId == kickedBy.CharId) {
// store outfit_id since it will be nulled soon
val outfit_id = kickedBy.outfit_id
removeMemberFromOutfit(outfit_id, kickedId).map {
case (deleted, _) =>
if (deleted > 0) {
PlayerControl.sendResponse(kickedBy.Zone, kickedBy.Name,
OutfitEvent(outfit_id, Leaving())
kickedBy.Zone.AvatarEvents ! BundledEnvelope(
MessageEnvelope(kickedBy.Name, SendResponse(OutfitEvent(outfit_id, Leaving()))),
MessageEnvelope(
kickedBy.Zone.id,
PlanetsideAttribute(kickedBy.GUID, 39, 0)
),
MessageEnvelope(
kickedBy.Zone.id,
kickedBy.GUID,
AvatarAction.PlanetsideStringAttribute(0, "")
)
)
session.chat.LeaveChannel(OutfitChannel(outfit_id))
kickedBy.outfit_name = ""
kickedBy.outfit_id = 0
zones.filter(z => z.AllPlayers.nonEmpty).flatMap(_.AllPlayers)
.filter(p => p.outfit_id == outfit_id).foreach(outfitMember =>
PlayerControl.sendResponse(outfitMember.Zone, outfitMember.Name,
OutfitMemberEvent(outfit_id, kickedId, OutfitMemberEventAction.Kicked()))
)
kickedBy.Zone.AvatarEvents ! MessageEnvelope(
kickedBy.Zone.id,
PlanetsideAttribute(kickedBy.GUID, 39, 0)
)
kickedBy.Zone.AvatarEvents ! MessageEnvelope(
kickedBy.Zone.id,
kickedBy.GUID,
AvatarAction.PlanetsideStringAttribute(0, "")
)
zones
.filter(z => z.AllPlayers.nonEmpty)
.flatMap(_.AllPlayers)
.filter(p => p.outfit_id == outfit_id)
.foreach(outfitMember =>
PlayerControl.sendResponse(outfitMember.Zone, outfitMember.Name,
OutfitMemberEvent(outfit_id, kickedId, OutfitMemberEventAction.Kicked())
)
)
}
}.recover { case e =>
e.printStackTrace()
}
}
else {
removeMemberFromOutfit(kickedBy.outfit_id, kickedId).map {
removeMemberFromOutfit(outfit_id, kickedId).map {
case (deleted, _) =>
if (deleted > 0) {
findPlayerByIdForOutfitAction(zones, kickedId, kickedBy).foreach { kicked =>
PlayerControl.sendResponse(kicked.Zone, kicked.Name,
OutfitEvent(kickedBy.outfit_id, Leaving())
kicked.Zone.AvatarEvents ! BundledEnvelope(
MessageEnvelope(kicked.Name, SendResponse(List(
OutfitEvent(outfit_id, Leaving()),
OutfitMembershipResponse(
OutfitMembershipResponse.PacketType.YouGotKicked, 0, 1,
kickedBy.CharId, kicked.CharId, kickedBy.Name, kicked.Name, flag = false
)
))),
MessageEnvelope(kicked.Zone.id,
PlanetsideAttribute(kicked.GUID, 39, 0)
),
MessageEnvelope(
kicked.Zone.id,
kicked.GUID,
AvatarAction.PlanetsideStringAttribute(0, "")
),
MessageEnvelope(kicked.Name,
AvatarAction.RemoveFromOutfitChat(outfit_id)
),
MessageEnvelope(kicked.Name, SendResponse(
OutfitMemberEvent(outfit_id, kickedId, OutfitMemberEventAction.Kicked())
))
)
PlayerControl.sendResponse(kicked.Zone, kicked.Name,
OutfitMembershipResponse(OutfitMembershipResponse.PacketType.YouGotKicked, 0, 1,
kickedBy.CharId, kicked.CharId, kickedBy.Name, kicked.Name, flag = false))
kicked.Zone.AvatarEvents ! MessageEnvelope(
kicked.Zone.id,
PlanetsideAttribute(kicked.GUID, 39, 0)
)
kicked.Zone.AvatarEvents ! MessageEnvelope(
kicked.Zone.id,
kicked.GUID,
AvatarAction.PlanetsideStringAttribute(0, "")
)
kicked.Zone.AvatarEvents ! MessageEnvelope(
kicked.Name, AvatarAction.RemoveFromOutfitChat(kickedBy.outfit_id))
kicked.outfit_id = 0
kicked.outfit_name = ""
PlayerControl.sendResponse(kicked.Zone, kicked.Name,
OutfitMemberEvent(kickedBy.outfit_id, kickedId, OutfitMemberEventAction.Kicked()))
}
val avatarName: Future[Option[String]] =
ctx.run(
quote { query[Avatar].filter(_.id == lift(kickedId)).map(_.name) }
).map(_.headOption)
ctx.run(quote { query[Avatar].filter(_.id == lift(kickedId)).map(_.name) }).map(_.headOption)
avatarName.foreach {
case Some(name) => PlayerControl.sendResponse(kickedBy.Zone, kickedBy.Name,
@ -302,10 +301,14 @@ object SessionOutfitHandlers {
case None => PlayerControl.sendResponse(kickedBy.Zone, kickedBy.Name,
OutfitMembershipResponse(OutfitMembershipResponse.PacketType.YouKicked, 0, 1, kickedBy.CharId, kickedId, "NameNotFound", "", flag = true))
}
zones.filter(z => z.AllPlayers.nonEmpty).flatMap(_.AllPlayers)
.filter(p => p.outfit_id == kickedBy.outfit_id).foreach(outfitMember =>
PlayerControl.sendResponse(outfitMember.Zone, outfitMember.Name,
OutfitMemberEvent(kickedBy.outfit_id, kickedId, OutfitMemberEventAction.Kicked()))
zones
.filter(z => z.AllPlayers.nonEmpty)
.flatMap(_.AllPlayers)
.filter(p => p.outfit_id == kickedBy.outfit_id)
.foreach(outfitMember =>
PlayerControl.sendResponse(outfitMember.Zone, outfitMember.Name,
OutfitMemberEvent(kickedBy.outfit_id, kickedId, OutfitMemberEventAction.Kicked())
)
)
// this needs to be the kicked player
// session.chat.LeaveChannel(OutfitChannel(kickedBy.outfit_id))
@ -319,18 +322,13 @@ object SessionOutfitHandlers {
}
def HandleOutfitPromote(zones: Seq[Zone], promotedId: Long, newRank: Int, promoter: Player): Unit = {
val outfit_id = promoter.outfit_id
findPlayerByIdForOutfitAction(zones, promotedId, promoter).foreach { promoted =>
if (newRank == 7) {
// demote owner to rank 6
// promote promoted to rank 7
// update outfit
updateOutfitOwner(outfit_id, promoter.avatar.id, promoted.avatar.id)
// TODO: does every member get the notification like this?
getOutfitMemberPoints(outfit_id, promoter.avatar.id).map {
owner_points =>
@ -346,7 +344,6 @@ object SessionOutfitHandlers {
})
})
}
// update promoter rank
PlayerControl.sendResponse(
promoter.Zone, promoter.Name,
@ -360,17 +357,19 @@ object SessionOutfitHandlers {
// TODO: does every member get the notification like this?
getOutfitMemberPoints(outfit_id, promoted.avatar.id).map {
member_points =>
// tell everyone about the new rank of the promoted member
zones.foreach(zone => {
zone.AllPlayers
zones.foreach { zone =>
// tell everyone about the new rank of the promoted member
val messages = zone.AllPlayers
.filter(_.outfit_id == outfit_id)
.foreach(player => {
PlayerControl.sendResponse(
zone, player.Name,
.map { player =>
MessageEnvelope(player.Name, SendResponse(
OutfitMemberEvent(outfit_id, promoted.avatar.id,
OutfitMemberEventAction.Update(promoted.Name, newRank, member_points, 0, OutfitMemberEventAction.PacketType.Padding, 0)))
})
})
OutfitMemberEventAction.Update(promoted.Name, newRank, member_points, 0, OutfitMemberEventAction.PacketType.Padding, 0)
)
))
}
zone.AvatarEvents ! BundledEnvelope(messages)
}
}
// update promoted rank
@ -386,7 +385,6 @@ object SessionOutfitHandlers {
memberCount <- ctx.run(query[Outfitmember].filter(_.outfit_id == lift(outfitId)).size)
pointsTotal <- ctx.run(querySchema[OutfitpointMv]("outfitpoint_mv").filter(_.outfit_id == lift(outfitId)))
} yield (outfitOpt, memberCount, pointsTotal.headOption.map(_.points).getOrElse(0L))
val membersF = ctx.run(getOutfitMembersWithDetails(outfitId))
for {
@ -395,43 +393,42 @@ object SessionOutfitHandlers {
} yield {
outfitOpt.foreach { outfit =>
val seconds: Long = outfit.created.atZone(ZoneId.systemDefault()).toInstant.toEpochMilli / 1000
PlayerControl.sendResponse(player.Zone, player.Name,
OutfitEvent(outfit.id, Initial(OutfitInfo(
outfit.name,
totalPoints,
totalPoints,
memberCount,
OutfitRankNames(
outfit.rank0.getOrElse(""),
outfit.rank1.getOrElse(""),
outfit.rank2.getOrElse(""),
outfit.rank3.getOrElse(""),
outfit.rank4.getOrElse(""),
outfit.rank5.getOrElse(""),
outfit.rank6.getOrElse(""),
outfit.rank7.getOrElse(""),
),
outfit.motd.getOrElse(""),
14, unk11 = true, 0, seconds, 0, 0, 0))))
members.foreach { case (avatarId, avatarName, points, rank, login) =>
val outfitEventInitial = OutfitEvent(outfit.id, Initial(OutfitInfo(
outfit.name,
totalPoints,
totalPoints,
memberCount,
OutfitRankNames(
outfit.rank0.getOrElse(""),
outfit.rank1.getOrElse(""),
outfit.rank2.getOrElse(""),
outfit.rank3.getOrElse(""),
outfit.rank4.getOrElse(""),
outfit.rank5.getOrElse(""),
outfit.rank6.getOrElse(""),
outfit.rank7.getOrElse(""),
),
outfit.motd.getOrElse(""),
14, unk11 = true, 0, seconds, 0, 0, 0))
)
val memberEventList = members.map { case (avatarId, avatarName, points, rank, login) =>
val lastLogin = findPlayerByIdForOutfitAction(zones, avatarId, player) match {
case Some(_) => 0L
case None if player.Name == avatarName => 0L
case None => (System.currentTimeMillis() - login.atZone(ZoneId.systemDefault()).toInstant.toEpochMilli) / 1000
}
PlayerControl.sendResponse(player.Zone, player.Name,
OutfitMemberEvent(outfit.id, avatarId,
OutfitMemberEventAction.Update(
avatarName,
rank,
points,
lastLogin,
OutfitMemberEventAction.PacketType.Padding, 0)))
OutfitMemberEvent(outfit.id, avatarId,
OutfitMemberEventAction.Update(
avatarName,
rank,
points,
lastLogin,
OutfitMemberEventAction.PacketType.Padding, 0)
)
}
PlayerControl.sendResponse(player.Zone, player.Name,
OutfitEvent(outfit.id, Unk1()))
player.Zone.AvatarEvents ! MessageEnvelope(player.Name, SendResponse(
outfitEventInitial +: memberEventList :+ OutfitEvent(outfit.id, Unk1())
))
}
}
}
@ -442,16 +439,13 @@ object SessionOutfitHandlers {
futureResult.onComplete {
case Success(rows) =>
rows.foreach { case (outfitId, points, name, leaderName, memberCount) =>
PlayerControl.sendResponse(player.Zone, player.Name,
player.Zone.AvatarEvents ! MessageEnvelope(player.Name, SendResponse(
rows.map { case (outfitId, points, name, leaderName, memberCount) =>
OutfitListEvent(
OutfitListEventAction.ListElementOutfit(
outfitId,
points,
memberCount,
name,
leaderName)))
}
OutfitListEventAction.ListElementOutfit(outfitId, points, memberCount, name, leaderName)
)
}
))
case Failure(_) =>
PlayerControl.sendResponse(player.Zone, player.Name,
@ -461,9 +455,7 @@ object SessionOutfitHandlers {
}
def HandleOutfitMotd(zones: Seq[Zone], message: String, player: Player): Unit = {
val outfit_id = player.outfit_id
val outfitDetails = for {
_ <- updateOutfitMotd(outfit_id, message)
outfitOpt <- ctx.run(getOutfitById(outfit_id)).map(_.headOption)
@ -475,9 +467,8 @@ object SessionOutfitHandlers {
(outfitOpt, memberCount, totalPoints) <- outfitDetails
} yield {
outfitOpt.foreach { outfit =>
// send to all online players in outfit
val outfit_event = OutfitEvent(
val outfit_event = SendResponse(OutfitEvent(
outfit_id,
Update(
OutfitInfo(
@ -505,19 +496,15 @@ object SessionOutfitHandlers {
unk25 = 0
)
)
)
))
zones.foreach(zone => {
zone.AllPlayers
.filter(_.outfit_id == outfit_id)
.filter(_.outfit_window_open)
.foreach(player => {
PlayerControl.sendResponse(
zone, player.Name,
outfit_event
)
})
})
zones.foreach { zone =>
zone.AvatarEvents ! BundledEnvelope(
zone.AllPlayers
.filter { p => p.outfit_id == outfit_id && p.outfit_window_open }
.map(p => MessageEnvelope(p.Name, outfit_event))
)
}
}
}
@ -526,9 +513,7 @@ object SessionOutfitHandlers {
}
def HandleOutfitRank(zones: Seq[Zone], list: List[Option[String]], player: Player): Unit = {
val outfit_id = player.outfit_id
val outfitDetails = for {
_ <- updateOutfitRanks(outfit_id, list)
outfitOpt <- ctx.run(getOutfitById(outfit_id)).map(_.headOption)
@ -540,9 +525,8 @@ object SessionOutfitHandlers {
(outfitOpt, memberCount, totalPoints) <- outfitDetails
} yield {
outfitOpt.foreach { outfit =>
// send to all online players in outfit with window open
val outfit_event = OutfitEvent(
val outfit_event = SendResponse(OutfitEvent(
outfit_id,
Update(
OutfitInfo(
@ -570,19 +554,15 @@ object SessionOutfitHandlers {
unk25 = 0
)
)
)
))
zones.foreach(zone => {
zone.AllPlayers
.filter(_.outfit_id == outfit_id)
.filter(_.outfit_window_open)
.foreach(player => {
PlayerControl.sendResponse(
zone, player.Name,
outfit_event
)
})
})
zones.foreach { zone =>
zone.AvatarEvents ! BundledEnvelope(
zone.AllPlayers
.filter { p => p.outfit_id == outfit_id && p.outfit_window_open }
.map(p => MessageEnvelope(p.Name, outfit_event))
)
}
}
}
}
@ -618,34 +598,34 @@ object SessionOutfitHandlers {
.map {
case (Some(outfit), memberCount, points) =>
val seconds: Long = outfit.created.atZone(ZoneId.systemDefault()).toInstant.toEpochMilli / 1000
PlayerControl.sendResponse(player.Zone, player.Name,
OutfitEvent(outfitId, Update(OutfitInfo(
outfit.name, points, points, memberCount,
OutfitRankNames(outfit.rank0.getOrElse(""), outfit.rank1.getOrElse(""), outfit.rank2.getOrElse(""),
outfit.rank3.getOrElse(""), outfit.rank4.getOrElse(""), outfit.rank5.getOrElse(""),
outfit.rank6.getOrElse(""), outfit.rank7.getOrElse("")),
outfit.motd.getOrElse(""),
14, unk11 = true, 0, seconds, 0, 0, 0))))
PlayerControl.sendResponse(player.Zone, player.Name,
OutfitMemberUpdate(outfit.id, player.CharId, membership.rank, flag = true))
player.Zone.AvatarEvents ! BundledEnvelope(
MessageEnvelope(player.Name, SendResponse(List(
OutfitEvent(outfitId, Update(OutfitInfo(
outfit.name, points, points, memberCount,
OutfitRankNames(
outfit.rank0.getOrElse(""), outfit.rank1.getOrElse(""), outfit.rank2.getOrElse(""),
outfit.rank3.getOrElse(""), outfit.rank4.getOrElse(""), outfit.rank5.getOrElse(""),
outfit.rank6.getOrElse(""), outfit.rank7.getOrElse("")
),
outfit.motd.getOrElse(""),
14, unk11 = true, 0, seconds, 0, 0, 0
))),
OutfitMemberUpdate(outfit.id, player.CharId, membership.rank, flag = true)
))),
MessageEnvelope(
player.Zone.id,
PlanetsideAttribute(player.GUID, 39, outfit.id)
),
MessageEnvelope(
player.Zone.id,
player.GUID,
AvatarAction.PlanetsideStringAttribute(0, outfit.name)
)
)
session.chat.JoinChannel(OutfitChannel(outfit.id))
player.outfit_id = outfit.id
player.outfit_name = outfit.name
player.Zone.AvatarEvents ! MessageEnvelope(
player.Zone.id,
PlanetsideAttribute(player.GUID, 39, outfit.id)
)
player.Zone.AvatarEvents ! MessageEnvelope(
player.Zone.id,
player.GUID,
AvatarAction.PlanetsideStringAttribute(0, outfit.name)
)
case (None, _, _) =>
PlayerControl.sendResponse(player.Zone, player.Name,
ChatMsg(ChatMessageType.UNK_227, "Failed to load outfit"))
@ -876,7 +856,7 @@ object SessionOutfitHandlers {
query[Outfit]
.filter(_.id == lift(outfit_id))
.update(
_.rank0 -> lift(colorized(0)),
_.rank0 -> lift(colorized.head),
_.rank1 -> lift(colorized(1)),
_.rank2 -> lift(colorized(2)),
_.rank3 -> lift(colorized(3)),

View file

@ -24,7 +24,7 @@ import net.psforever.objects.zones.blockmap.BlockMapEntity
import net.psforever.packet.game.GenericAction.FirstPersonViewWithEffect
import net.psforever.packet.game.{CampaignStatistic, ChangeFireStateMessage_Start, CloudInfo, GenericActionMessage, GenericObjectActionEnum, HackState7, MailMessage, ObjectDetectedMessage, SessionStatistic, StormInfo, TrainingZoneMessage, TriggeredSound, WeatherMessage}
import net.psforever.services.avatar.support.{CorpseEnvelope, ReleaseEnvelope}
import net.psforever.services.base.envelope.MessageEnvelope
import net.psforever.services.base.envelope.{BundledEnvelope, MessageEnvelope}
import net.psforever.services.base.message.{GenericObjectAction, ObjectDelete, PlanetsideAttribute, SendResponse}
import net.psforever.services.chat.DefaultChannel
@ -4005,21 +4005,20 @@ class ZoningOperations(
}
GoToDeploymentMap()
val pZone = player.Zone
val msg = GenericObjectAction(player.GUID, GenericObjectActionEnum.PlayerDeconstructs.id)
sendResponse(GenericActionMessage(FirstPersonViewWithEffect))
pZone.blockMap.sector(player).livePlayerList.collect { case t if t.GUID != player.GUID =>
pZone.LocalEvents ! MessageEnvelope(
t.Name,
t.GUID,
GenericObjectAction(player.GUID, GenericObjectActionEnum.PlayerDeconstructs.id)
)
}
pZone.AllPlayers.collect { case t if t.GUID != player.GUID && !t.allowInteraction =>
pZone.LocalEvents ! MessageEnvelope(
t.Name,
t.GUID,
GenericObjectAction(player.GUID, GenericObjectActionEnum.PlayerDeconstructs.id)
)
}
val (localMessageRecipients, localMesages) = pZone.blockMap.sector(player).livePlayerList
.collect {
case t if t.GUID != player.GUID =>
(t.Name, MessageEnvelope(t.Name, msg))
}
.unzip
val otherMessages: Seq[MessageEnvelope] = pZone.AllPlayers
.collect {
case t if t.GUID != player.GUID && !t.allowInteraction && !localMessageRecipients.contains(t.Name) =>
MessageEnvelope(t.Name, msg)
}
pZone.LocalEvents ! BundledEnvelope(localMesages ++ otherMessages)
}
def stopDeconstructing(): Unit = {

View file

@ -293,11 +293,12 @@ object DeployableBehavior {
MessageEnvelope(toFaction.toString, LocalAction.DeployableMapIcon(DeploymentAction.Build, info))
)
//remove deployable from original owner's toolbox and UI counter
zone.AllPlayers.filter(p => obj.OriginalOwnerName.contains(p.Name))
.foreach { originalOwner =>
localEvents ! BundledEnvelope(zone.AllPlayers
.filter(p => obj.OriginalOwnerName.contains(p.Name))
.map { originalOwner =>
originalOwner.avatar.deployables.Remove(obj)
originalOwner.Zone.LocalEvents ! MessageEnvelope(originalOwner.Name, LocalAction.DeployableUIFor(obj.Definition.Item))
}
MessageEnvelope(originalOwner.Name, LocalAction.DeployableUIFor(obj.Definition.Item))
})
}
}
}

View file

@ -7,7 +7,7 @@ import net.psforever.objects.sourcing.{PlayerSource, SourceEntry}
import net.psforever.objects.vital.interaction.{DamageInteraction, DamageResult}
import net.psforever.packet.game.DamageWithPositionMessage
import net.psforever.services.avatar.AvatarAction
import net.psforever.services.base.envelope.MessageEnvelope
import net.psforever.services.base.envelope.{BundledEnvelope, MessageEnvelope}
import net.psforever.services.base.message.{HintsAtAttacker, SendResponse}
/**
@ -37,32 +37,34 @@ object DamageableMountable {
val zone = target.Zone
val events = zone.AvatarEvents
val occupants = target.Seats.values.toSeq.flatMap { seat => seat.occupants.filter(_.isAlive) }
((cause.adversarial match {
case Some(adversarial) => Some(adversarial.attacker)
case None => None
}) match {
case Some(pSource: PlayerSource) => //player damage
val name = pSource.Name
(zone.LivePlayers.find(_.Name == name).orElse(zone.Corpses.find(_.Name == name)) match {
case Some(player) =>
HintsAtAttacker(player.GUID)
case None =>
SendResponse(DamageWithPositionMessage(countableDamage, pSource.Position))
}) match {
case msg @ HintsAtAttacker(guid) =>
occupants.map { tplayer => (tplayer.Name, guid, msg) }
case msg =>
occupants.map { tplayer => (tplayer.Name, Default.GUID0, msg) }
}
case Some(source) => //object damage
val msg = SendResponse(DamageWithPositionMessage(countableDamage, source.Position))
occupants.map { tplayer => (tplayer.Name, Default.GUID0, msg) }
case None =>
List.empty
}).foreach {
case (channel, filter, msg) =>
events ! MessageEnvelope(channel, filter, msg)
}
events ! BundledEnvelope(
((cause.adversarial match {
case Some(adversarial) => Some(adversarial.attacker)
case None => None
}) match {
case Some(pSource: PlayerSource) => //player damage
val name = pSource.Name
(zone.LivePlayers.find(_.Name == name).orElse(zone.Corpses.find(_.Name == name)) match {
case Some(player) =>
HintsAtAttacker(player.GUID)
case None =>
SendResponse(DamageWithPositionMessage(countableDamage, pSource.Position))
}) match {
case msg @ HintsAtAttacker(guid) =>
occupants.map { tplayer => (tplayer.Name, guid, msg) }
case msg =>
occupants.map { tplayer => (tplayer.Name, Default.GUID0, msg) }
}
case Some(source) => //object damage
val msg = SendResponse(DamageWithPositionMessage(countableDamage, source.Position))
occupants.map { tplayer => (tplayer.Name, Default.GUID0, msg) }
case None =>
List.empty
}).map {
case (channel, filter, msg) =>
MessageEnvelope(channel, filter, msg)
}
)
}
/**

View file

@ -253,7 +253,7 @@ trait DamageableVehicle
)
if (obj.Shields > 0) {
obj.Shields = 0
zone.VehicleEvents ! MessageEnvelope(
events ! MessageEnvelope(
zone.id,
PlanetsideAttribute(obj.GUID, obj.Definition.shieldUiAttribute, 0)
)

View file

@ -9,7 +9,7 @@ import net.psforever.objects.vital.interaction.DamageResult
import net.psforever.objects.zones.Zone
import net.psforever.packet.game.DamageWithPositionMessage
import net.psforever.types.Vector3
import net.psforever.services.base.envelope.MessageEnvelope
import net.psforever.services.base.envelope.{BundledEnvelope, MessageEnvelope}
import net.psforever.services.base.message.{ObjectDelete, PlanetsideAttribute, SendResponse}
import net.psforever.services.base.support.SupportActor
import net.psforever.services.vehicle.support.{TurretEnvelope, TurretUpgrader}
@ -72,11 +72,12 @@ trait DamageableWeaponTurret
if (announceConfrontation) {
if (aggravated) {
val msg = SendResponse(DamageWithPositionMessage(damageToHealth, Vector3.Zero))
obj.Seats.values
events ! BundledEnvelope(obj.Seats.values
.collect { case seat if seat.occupant.nonEmpty => seat.occupant.get.Name }
.foreach { channel =>
events ! MessageEnvelope(channel, msg)
.map { channel =>
MessageEnvelope(channel, msg)
}
)
}
else {
//activity on map
@ -124,14 +125,12 @@ object DamageableWeaponTurret {
val zone = target.Zone
val zoneId = zone.id
val avatarEvents = zone.AvatarEvents
target.Weapons.values
.filter {
_.Equipment.nonEmpty
avatarEvents ! BundledEnvelope(target.Weapons.values
.filter(_.Equipment.nonEmpty)
.map { slot =>
MessageEnvelope(zoneId, ObjectDelete(slot.Equipment.get.GUID))
}
.foreach(slot => {
val wep = slot.Equipment.get
avatarEvents ! MessageEnvelope(zoneId, ObjectDelete(wep.GUID))
})
)
target match {
case turret: WeaponTurret =>
if (turret.Upgrade != TurretUpgrade.None) {

View file

@ -14,7 +14,7 @@ import net.psforever.objects.vital.interaction.DamageInteraction
import net.psforever.objects.vital.prop.DamageWithPosition
import net.psforever.objects.zones.Zone
import net.psforever.packet.game.ChatMsg
import net.psforever.services.base.envelope.MessageEnvelope
import net.psforever.services.base.envelope.{BundledEnvelope, MessageEnvelope}
import net.psforever.services.base.message.SendResponse
import net.psforever.services.local.LocalAction
import net.psforever.types.{ChatMessageType, PlanetSideEmpire, PlanetSideGeneratorState, Vector3}
@ -143,9 +143,9 @@ object ForceDomeControl {
ChatMessageType.UNK_227,
"Expected capitol force dome state change will resume."
))
building.PlayersInSOI.foreach { player =>
events ! MessageEnvelope(player.Name, message)
}
events ! BundledEnvelope(building.PlayersInSOI.map { player =>
MessageEnvelope(player.Name, message)
})
}
/**

View file

@ -5,7 +5,7 @@ import net.psforever.objects.Tool
import net.psforever.objects.equipment.EquipmentSlot
import net.psforever.objects.serverobject.turret.WeaponTurret
import net.psforever.objects.vehicles.MountedWeapons
import net.psforever.services.base.envelope.MessageEnvelope
import net.psforever.services.base.envelope.{BundledEnvelope, MessageEnvelope}
import net.psforever.services.vehicle.VehicleAction
/**
@ -41,14 +41,15 @@ object RepairableWeaponTurret {
val zoneId = zone.id
val tguid = target.GUID
val events = zone.VehicleEvents
target.Weapons
events ! BundledEnvelope(target.Weapons
.map({ case (index, slot: EquipmentSlot) => (index, slot.Equipment) })
.collect {
case (index: Int, Some(tool: Tool)) =>
events ! MessageEnvelope(
MessageEnvelope(
zoneId,
VehicleAction.EquipmentInSlot(tguid, index, tool)
)
}
)
}
}

View file

@ -12,7 +12,7 @@ import net.psforever.objects.{GlobalDefinitions, Ntu, NtuContainer, NtuStorageBe
import net.psforever.types.{ExperienceType, PlanetSideEmpire}
import net.psforever.services.Service
import net.psforever.services.avatar.AvatarAction
import net.psforever.services.base.envelope.MessageEnvelope
import net.psforever.services.base.envelope.{BundledEnvelope, MessageEnvelope}
import net.psforever.services.base.message.PlanetsideAttribute
import net.psforever.util.Config
@ -203,12 +203,16 @@ class ResourceSiloControl(resourceSilo: ResourceSilo)
(Config.app.game.experience.sep.ntuSiloDepositReward.toFloat *
amount * resourceSilo.Definition.ChargeTime.toSeconds.toFloat / resourceSilo.MaxNtuCapacitor
).toLong
vehicle.Zone.AvatarEvents ! MessageEnvelope(
owner.name,
AvatarAction.AwardBep(owner.charId, deposit, ExperienceType.Normal)
vehicle.Zone.AvatarEvents ! BundledEnvelope(
MessageEnvelope(
owner.name,
AvatarAction.AwardBep(owner.charId, deposit, ExperienceType.Normal)
),
MessageEnvelope(
owner.name,
AvatarAction.ShareAntExperienceWithSquad(owner, deposit, vehicle)
)
)
vehicle.Zone.AvatarEvents ! MessageEnvelope(
owner.name, AvatarAction.ShareAntExperienceWithSquad(owner, deposit, vehicle))
zones.exp.ToDatabase.reportNtuActivity(owner.charId, resourceSilo.Zone.Number, resourceSilo.Owner.GUID.guid, deposit)
}
}

View file

@ -5,7 +5,7 @@ import net.psforever.objects.Player
import net.psforever.objects.avatar.scoring.Kill
import net.psforever.objects.sourcing.UniquePlayer
import net.psforever.packet.game.GenericObjectActionMessage
import net.psforever.services.base.envelope.MessageEnvelope
import net.psforever.services.base.envelope.{BundledEnvelope, MessageEnvelope}
import net.psforever.services.base.message.SendResponse
import net.psforever.types.{PlanetSideEmpire, Vector3}
@ -115,9 +115,9 @@ trait FacilityHackParticipation extends ParticipationLogic {
GenericObjectActionMessage(mainTerm, 58)
))
val events = building.Zone.AvatarEvents
list.foreach { p =>
events ! MessageEnvelope(p.Name, pkts)
}
events ! BundledEnvelope(list.map { p =>
MessageEnvelope(p.Name, pkts)
})
}
}
}

View file

@ -15,7 +15,7 @@ import net.psforever.objects.avatar.scoring.Kill
import net.psforever.objects.serverobject.hackable.Hackable
import net.psforever.objects.zones.exp.ToDatabase
import net.psforever.packet.game.ChatMsg
import net.psforever.services.base.envelope.MessageEnvelope
import net.psforever.services.base.envelope.{BundledEnvelope, MessageEnvelope}
import net.psforever.services.base.message.SendResponse
import scala.collection.mutable
@ -307,14 +307,15 @@ final case class MajorFacilityHackParticipation(building: Building) extends Faci
events ! MessageEnvelope(hacker.Name, AvatarAction.AwardCep(hackerId, finalCep))
}*/
//bystanders (cep if squad leader, bep otherwise)
contributingPlayers
events ! BundledEnvelope(contributingPlayers
//.filterNot { _.CharId == hackerId }
.foreach { player =>
.map { player =>
val charId = player.CharId
val contributionMultiplier = contributionPerPlayerByTime.getOrElse(charId, 1f)
val outputValue = (finalCep * contributionMultiplier).toLong
events ! MessageEnvelope(player.Name, AvatarAction.FacilityCaptureRewards(buildingId, zoneNumber, outputValue))
MessageEnvelope(player.Name, AvatarAction.FacilityCaptureRewards(buildingId, zoneNumber, outputValue))
}
)
//flag carrier (won't be in soi, but earns cep from capture)
flagCarrier.collect {
case player if !isResecured =>
@ -440,8 +441,8 @@ object MajorFacilityHackParticipation {
): Unit = {
val events = building.Zone.LocalEvents
val message = SendResponse(msg)
targets.foreach { player =>
events ! MessageEnvelope(player.Name, message)
}
events ! BundledEnvelope(targets.map { player =>
MessageEnvelope(player.Name, message)
})
}
}

View file

@ -5,7 +5,7 @@ import net.psforever.objects.serverobject.structures.Building
import net.psforever.objects.sourcing.PlayerSource
import net.psforever.objects.zones.exp.ToDatabase
import net.psforever.services.avatar.AvatarAction
import net.psforever.services.base.envelope.MessageEnvelope
import net.psforever.services.base.envelope.{BundledEnvelope, MessageEnvelope}
import net.psforever.types.{PlanetSideEmpire, Vector3}
import net.psforever.util.Config
@ -154,18 +154,19 @@ final case class TowerHackParticipation(building: Building) extends FacilityHack
expType = "cep"
)
//bystanders (cep if squad leader, bep otherwise)
soiPlayers
events ! BundledEnvelope(soiPlayers
.filterNot(_.CharId == hackerId)
.foreach { player =>
.map { player =>
val charId = player.CharId
val contributionTimeMultiplier = contributionPerPlayerByTime.getOrElse(charId, 0.5f)
val contributionDistanceMultiplier = contributionPerPlayerByDistanceFromGoal.getOrElse(charId, 0.5f)
val outputValue = (finalCep * contributionTimeMultiplier * contributionDistanceMultiplier).toLong
events ! MessageEnvelope(
MessageEnvelope(
player.Name,
AvatarAction.FacilityCaptureRewards(buildingId, zoneNumber, outputValue)
)
}
)
} else {
//no need to calculate a fancy score
ToDatabase.reportFacilityCaptureInBulk(

View file

@ -6,7 +6,7 @@ import net.psforever.objects.serverobject.damage.Damageable
import net.psforever.objects.sourcing.AmenitySource
import net.psforever.objects.vital.interaction.DamageResult
import net.psforever.packet.game.HackState1
import net.psforever.services.base.envelope.MessageEnvelope
import net.psforever.services.base.envelope.{BundledEnvelope, MessageEnvelope}
import net.psforever.services.base.message.{PlanetsideAttribute, SendResponse}
import net.psforever.services.local.support.{HackClearActor, HackClearEnvelope}
import org.log4s.Logger
@ -432,12 +432,12 @@ object ProximityTerminalControl {
val events = unit.Zone.AvatarEvents
val channel = target.Name
ancient.foreach { case (weapon, slots) =>
slots.foreach { slot =>
events ! MessageEnvelope(
events ! BundledEnvelope(slots.map { slot =>
MessageEnvelope(
channel,
SendResponse(InventoryStateMessage(slot.Box.GUID, weapon.GUID, slot.Box.Capacity))
)
}
})
}
!result.flatMap { _._2 }.exists { slot => slot.Magazine < slot.MaxMagazine() }
}
@ -457,14 +457,14 @@ object ProximityTerminalControl {
)
val events = unit.Zone.VehicleEvents
val channel = target.Actor.toString
result.foreach { case (weapon, slots) =>
slots.foreach { slot =>
events ! MessageEnvelope(
events ! BundledEnvelope(result.flatMap { case (weapon, slots) =>
slots.map { slot =>
MessageEnvelope(
channel,
SendResponse(InventoryStateMessage(slot.Box.GUID, weapon.GUID, slot.Box.Capacity))
)
}
}
})
!result.flatMap { _._2 }.exists { slot => slot.Magazine < slot.MaxMagazine() }
}

View file

@ -16,7 +16,7 @@ import net.psforever.objects.vital.interaction.DamageResult
import net.psforever.objects.zones.Zone
import net.psforever.objects.{GlobalDefinitions, Player, SimpleItem}
import net.psforever.packet.game.HackState1
import net.psforever.services.base.envelope.MessageEnvelope
import net.psforever.services.base.envelope.{BundledEnvelope, MessageEnvelope}
import net.psforever.services.base.message.SetEmpire
import net.psforever.services.vehicle.VehicleAction
import net.psforever.types.{PlanetSideEmpire, PlanetSideGUID}
@ -145,14 +145,14 @@ class ImplantTerminalMechControl(mech: ImplantTerminalMech)
val zone = mech.Zone
val zoneId = zone.id
val events = zone.VehicleEvents
mech.Seats.values.foreach(seat =>
events ! BundledEnvelope(mech.Seats.values.flatMap(seat =>
seat.occupant.collect {
case player =>
seat.unmount(player)
player.VehicleSeated = None
events ! MessageEnvelope(zoneId, player.GUID, VehicleAction.KickPassenger(4, unk2=false, guid))
MessageEnvelope(zoneId, player.GUID, VehicleAction.KickPassenger(4, unk2=false, guid))
}
)
))
}
def powerTurnOnCallback(): Unit = {
@ -225,9 +225,9 @@ class ImplantTerminalMechControl(mech: ImplantTerminalMech)
setToFaction: PlanetSideEmpire.Value
): Unit = {
val events = zone.LocalEvents
opposingFactionsAre(setToFaction).foreach { faction =>
events ! MessageEnvelope(faction.toString, SetEmpire(guid, faction))
}
events ! BundledEnvelope(opposingFactionsAre(setToFaction).toSeq.map { faction =>
MessageEnvelope(faction.toString, SetEmpire(guid, faction))
})
}
private def noAccessByOpposingFactions(
@ -236,9 +236,9 @@ class ImplantTerminalMechControl(mech: ImplantTerminalMech)
setToFaction: PlanetSideEmpire.Value
): Unit = {
val events = zone.LocalEvents
opposingFactionsAre(setToFaction).foreach { faction =>
events ! MessageEnvelope(faction.toString, SetEmpire(guid, setToFaction))
}
events ! BundledEnvelope(opposingFactionsAre(setToFaction).toSeq.map { faction =>
MessageEnvelope(faction.toString, SetEmpire(guid, setToFaction))
})
}
private def opposingFactionsAre(faction: PlanetSideEmpire.Value): PlanetSideEmpire.ValueSet = {
@ -273,13 +273,13 @@ class ImplantTerminalMechControl(mech: ImplantTerminalMech)
): Unit = {
val zoneId = zone.id
val events = zone.LocalEvents
obj.Seats.values.foreach(seat =>
events ! BundledEnvelope(obj.Seats.values.flatMap(seat =>
seat.occupant.collect {
case player if test(player.Faction) =>
seat.unmount(player)
player.VehicleSeated = None
events ! MessageEnvelope(zoneId, player.GUID, VehicleAction.KickPassenger(4, unk2 = false, guid))
MessageEnvelope(zoneId, player.GUID, VehicleAction.KickPassenger(4, unk2 = false, guid))
}
)
))
}
}

View file

@ -13,7 +13,7 @@ import net.psforever.objects.serverobject.turret.auto.AutomatedTurret.Target
import net.psforever.objects.serverobject.turret.auto.{AffectedByAutomaticTurretFire, AutomatedTurret, AutomatedTurretBehavior}
import net.psforever.objects.vital.interaction.DamageResult
import net.psforever.packet.game.{ChangeFireModeMessage, HackState1}
import net.psforever.services.base.envelope.MessageEnvelope
import net.psforever.services.base.envelope.{BundledEnvelope, MessageEnvelope}
import net.psforever.services.base.message.SendResponse
import net.psforever.services.vehicle.support.TurretUpgrader
import net.psforever.services.vehicle.VehicleAction
@ -336,15 +336,15 @@ class FacilityTurretControl(turret: FacilityTurret)
val zone = turret.Zone
val zoneId = zone.id
val events = zone.VehicleEvents
turret.Seats.values.zipWithIndex.foreach {
events ! BundledEnvelope(turret.Seats.values.zipWithIndex.flatMap {
case (seat, seat_num) =>
seat.occupant.collect {
case player =>
seat.unmount(player)
player.VehicleSeated = None
events ! MessageEnvelope(zoneId, player.GUID, VehicleAction.KickPassenger(seat_num, unk2=true, guid))
MessageEnvelope(zoneId, player.GUID, VehicleAction.KickPassenger(seat_num, unk2=true, guid))
}
}
})
captureTerminalChanges(terminal, super.captureTerminalIsHacked, actionDelays = 3000L)
}

View file

@ -4,7 +4,7 @@ package net.psforever.objects.serverobject.turret
import akka.actor.Cancellable
import net.psforever.objects.serverobject.ServerObjectControl
import net.psforever.objects.{Default, Player, Tool}
import net.psforever.services.base.envelope.MessageEnvelope
import net.psforever.services.base.envelope.{BundledEnvelope, MessageEnvelope}
import net.psforever.services.local.LocalAction
import net.psforever.types.Vector3
@ -50,14 +50,14 @@ class VanuSentryControl(turret: FacilityTurret)
if (weapon.Magazine < weapon.MaxMagazine && System.currentTimeMillis() - weapon.LastDischarge > 3000L) {
weapon.Magazine += 1
val seat = TurretObject.Seat(0).get
seat.occupant.collect {
TurretObject.Zone.LocalEvents ! BundledEnvelope(seat.occupant.collect {
case player: Player =>
TurretObject.Zone.LocalEvents ! MessageEnvelope(
MessageEnvelope(
TurretObject.Zone.id,
player.GUID,
LocalAction.RechargeVehicleWeapon(TurretObject.GUID, weapon.GUID)
)
}
})
}
else if (weapon.Magazine == weapon.MaxMagazine && weaponAmmoRechargeTimer != Default.Cancellable) {
weaponAmmoRechargeTimer.cancel()

View file

@ -5,7 +5,7 @@ import net.psforever.objects.avatar.Certification
import net.psforever.objects.ce.Deployable
import net.psforever.objects.{Player, Tool, TurretDeployable}
import net.psforever.packet.game.{HackMessage, HackState, HackState1, HackState7, InventoryStateMessage}
import net.psforever.services.base.envelope.MessageEnvelope
import net.psforever.services.base.envelope.{BundledEnvelope, MessageEnvelope}
import net.psforever.services.base.message.{SendResponse, SetEmpire}
import net.psforever.services.local.LocalAction
import net.psforever.services.vehicle.support.{TurretEnvelope, TurretUpgrader}
@ -100,18 +100,18 @@ object WeaponTurrets {
val certs = hacker.avatar.certifications
if (certs.contains(Certification.ExpertHacking) || certs.contains(Certification.ElectronicsExpert)) {
// Forcefully dismount all seated occupants from the turret
target.Seats.values.foreach { seat =>
zone.VehicleEvents ! BundledEnvelope(target.Seats.values.flatMap { seat =>
seat.occupant.collect {
player: Player =>
seat.unmount(player)
player.VehicleSeated = None
zone.VehicleEvents ! MessageEnvelope(
MessageEnvelope(
zone.id,
player.GUID,
VehicleAction.KickPassenger(4, unk2 = false, target.GUID)
)
}
}
})
//hacker owns the deployable now
target.OwnerGuid = None
target.Actor ! Deployable.Ownership(hacker)

View file

@ -5,7 +5,7 @@ import akka.actor.{Actor, ActorRef, Cancellable, Props}
import net.psforever.objects.Default
import net.psforever.types.{PlanetSideEmpire, Vector3}
import net.psforever.services.ServiceManager
import net.psforever.services.base.envelope.MessageEnvelope
import net.psforever.services.base.envelope.{BundledEnvelope, MessageEnvelope}
import net.psforever.services.galaxy.GalaxyAction
import scala.collection.mutable.ListBuffer
@ -305,12 +305,14 @@ class ZoneHotSpotProjector(zone: Zone, hotspots: ListBuffer[HotSpotInfo], blanki
def UpdateHotSpots(affectedFactions: Iterable[PlanetSideEmpire.Value], hotSpotInfos: Iterable[HotSpotInfo]): Unit = {
val zoneNumber = zone.Number
val hotSpotInfoList = hotSpotInfos.toList
affectedFactions.foreach(faction =>
galaxy ! MessageEnvelope(faction.toString, GalaxyAction.HotSpotUpdate(
galaxy ! BundledEnvelope(
affectedFactions.map(faction =>
MessageEnvelope(faction.toString, GalaxyAction.HotSpotUpdate(
zoneNumber,
1,
ZoneHotSpotProjector.SpecificHotSpotInfo(faction, hotSpotInfoList)
))
)
)
}
}

View file

@ -12,7 +12,7 @@ import net.psforever.objects.Default
import net.psforever.objects.serverobject.structures.{Building, WarpGate}
import net.psforever.objects.zones.Zone
import net.psforever.packet.game.ChatMsg
import net.psforever.services.base.envelope.{GenericResponseEnvelope, MessageEnvelope}
import net.psforever.services.base.envelope.{BundledEnvelope, GenericResponseEnvelope, MessageEnvelope}
import net.psforever.services.base.message.SendResponse
import net.psforever.services.galaxy.{GalaxyAction, GalaxyStamp}
import net.psforever.types.ChatMessageType
@ -576,16 +576,18 @@ class CavernRotationService(
def sendCavernRotationUpdatesToAll(galaxyService: ActorRef): Unit = {
val curr = System.currentTimeMillis()
val (lockedZones, unlockedZones) = managedZones.partition(_.locked)
unlockedZones.foreach { z =>
galaxyService ! MessageEnvelope("", GalaxyAction.UnlockedZoneUpdate(z.zone))
}
val sortedLocked = lockedZones.sortBy(z => z.start)
sortedLocked.take(2).foreach { z =>
galaxyService ! MessageEnvelope("", GalaxyAction.LockedZoneUpdate(z.zone, z.start + z.duration - curr))
}
sortedLocked.takeRight(2).foreach { z =>
galaxyService ! MessageEnvelope("", GalaxyAction.LockedZoneUpdate(z.zone, 0L))
}
galaxyService ! BundledEnvelope(
unlockedZones.map { z =>
MessageEnvelope("", GalaxyAction.UnlockedZoneUpdate(z.zone))
} ++
sortedLocked.take(2).map { z =>
MessageEnvelope("", GalaxyAction.LockedZoneUpdate(z.zone, z.start + z.duration - curr))
} ++
sortedLocked.takeRight(2).map { z =>
MessageEnvelope("", GalaxyAction.LockedZoneUpdate(z.zone, 0L))
}
)
}
/**

View file

@ -18,7 +18,7 @@ import net.psforever.services.base.envelope.{BundledEnvelope, MessageEnvelope}
import net.psforever.services.base.message.PlanetsideAttribute
import net.psforever.services.local.support.HackCaptureActor.GetHackingFaction
import net.psforever.services.local.LocalAction
import net.psforever.types.{ChatMessageType, PlanetSideEmpire, PlanetSideGUID}
import net.psforever.types.{ChatMessageType, PlanetSideEmpire}
import java.util.concurrent.{Executors, TimeUnit}
import scala.collection.Seq
@ -247,7 +247,6 @@ class HackCaptureActor extends Actor {
// Notify all clients that CC has had its hack state changed
terminal.Zone.LocalEvents ! MessageEnvelope(
terminal.Zone.id,
PlanetSideGUID(-1), /*what is this?, says the person who wrote it*/
PlanetsideAttribute(
terminal.GUID,
PlanetsideAttributeEnum.ControlConsoleHackUpdate.id,

View file

@ -10,7 +10,7 @@ import net.psforever.objects.serverobject.turret.{FacilityTurret, TurretUpgrade,
import net.psforever.objects.vehicles.MountedWeapons
import net.psforever.objects.zones.Zone
import net.psforever.services.base.{EventServiceSupport, GenericSupportEnvelopeOnly}
import net.psforever.services.base.envelope.MessageEnvelope
import net.psforever.services.base.envelope.{BundledEnvelope, MessageEnvelope}
import net.psforever.types.PlanetSideGUID
import net.psforever.services.base.support.{SimilarityComparator, SupportActor, SupportActorCaseConversions}
import net.psforever.services.vehicle.VehicleAction
@ -245,15 +245,16 @@ class TurretUpgrader extends SupportActor[TurretUpgrader.Entry] {
trace(s"Wall turret finished ${target.Upgrade} upgrade")
val targetGUID = target.GUID
if (target.Health > 0) {
target.Weapons
context.parent ! BundledEnvelope(target.Weapons
.map { case (index: Int, slot: EquipmentSlot) => (index, slot.Equipment) }
.collect {
case (index, Some(tool: Tool)) =>
context.parent ! MessageEnvelope(
MessageEnvelope(
zone.id,
VehicleAction.EquipmentInSlot(targetGUID, index, tool)
)
}
)
}
Finalize(target, entry.upgrade)
}