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.packet.game.{ChatMsg, SetChatFilterMessage}
import net.psforever.services.Service import net.psforever.services.Service
import net.psforever.services.avatar.AvatarAction 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.base.message.{ObjectDelete, SetEmpire}
import net.psforever.services.chat.{ChatChannel, DefaultChannel, SpectatorChannel, SquadChannel} import net.psforever.services.chat.{ChatChannel, DefaultChannel, SpectatorChannel, SquadChannel}
import net.psforever.types.ChatMessageType.{CMT_TOGGLESPECTATORMODE, CMT_TOGGLE_GM} 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 val events = continent.AvatarEvents
seeSpectatorsIn = Some(continent) seeSpectatorsIn = Some(continent)
events ! Service.Join(s"spectator") events ! Service.Join(s"spectator")
events ! BundledEnvelope(
continent continent
.AllPlayers .AllPlayers
.filter(_.spectator) .filter(_.spectator)
.foreach { spectator => .map { spectator =>
val guid = spectator.GUID val guid = spectator.GUID
val definition = spectator.Definition val definition = spectator.Definition
events ! MessageEnvelope( MessageEnvelope(
channel, channel,
guid, guid,
AvatarAction.LoadPlayer(definition.ObjectId, guid, definition.Packet.ConstructorData(spectator).get, None) AvatarAction.LoadPlayer(definition.ObjectId, guid, definition.Packet.ConstructorData(spectator).get, None)
) )
} }
)
true true
} }
@ -334,13 +336,15 @@ class ChatLogic(val ops: ChatOperations, implicit val context: ActorContext) ext
val events = continent.AvatarEvents val events = continent.AvatarEvents
seeSpectatorsIn = None seeSpectatorsIn = None
events ! Service.Leave("spectator") events ! Service.Leave("spectator")
events ! BundledEnvelope(
continent continent
.AllPlayers .AllPlayers
.filter(_.spectator) .filter(_.spectator)
.foreach { spectator => .map { spectator =>
val guid = spectator.GUID val guid = spectator.GUID
events ! MessageEnvelope(channel, guid, ObjectDelete(guid)) MessageEnvelope(channel, guid, ObjectDelete(guid))
} }
)
true 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.vehicles.AccessPermissionGroup
import net.psforever.objects.vital.InGameHistory 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.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.base.message.{SendResponse, SetEmpire}
import net.psforever.services.vehicle.VehicleAction import net.psforever.services.vehicle.VehicleAction
import net.psforever.types.{BailType, ChatMessageType, DriveState, PlanetSideGUID, Vector3} 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) ops.DismountAction(tplayer, obj, seatNum)
continent.actor ! ZoneActor.RemoveFromBlockMap(player) //character doesn't need it 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 //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 //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 //the player will fall to the ground and is perfectly vulnerable in this state
//additionally, our player must exist in the current zone //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 //having no in-game avatar target will throw us out of the map screen when deploying and cause softlock
events ! MessageEnvelope( events ! BundledEnvelope(
player.Name, MessageEnvelope(player.Name,
SendResponse(PlayerStateShiftMessage(ShiftState(unk=0, obj.Position, obj.Orientation.z, vel=None))) 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 */
) )
events ! MessageEnvelope(
continent.id,
pguid,
SendResponse(GenericObjectActionMessage(pguid, code=9)) //conceal the player
) )
sessionLogic.keepAliveFunc = sessionLogic.zoning.NormalKeepAlive 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.objects.vital.interaction.Adversarial
import net.psforever.packet.game.{AvatarImplantMessage, CreateShortcutMessage, ImplantAction, PlanetsideStringAttributeMessage} import net.psforever.packet.game.{AvatarImplantMessage, CreateShortcutMessage, ImplantAction, PlanetsideStringAttributeMessage}
import net.psforever.services.avatar.AvatarAction 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.services.base.message.{ChangeAmmo, ChangeFireState_Start, ChangeFireState_Stop, ObjectDelete, PlanetsideAttribute, ReloadTool, WeaponDryFire}
import net.psforever.types.ImplantType 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 = { def killedWhileMounted(obj: PlanetSideGameObject with Mountable, playerGuid: PlanetSideGUID): Unit = {
val events = continent.AvatarEvents
ops.killedWhileMounted(obj, playerGuid) ops.killedWhileMounted(obj, playerGuid)
//make player invisible on client continent.AvatarEvents ! BundledEnvelope(
events ! MessageEnvelope(player.Name, PlanetsideAttribute(playerGuid, 29, 1)) /* make player invisible on client */
//only the dead player should "see" their own body, so that the death camera has something to focus on MessageEnvelope(player.Name, PlanetsideAttribute(playerGuid, 29, 1)),
events ! MessageEnvelope(continent.id, playerGuid, ObjectDelete(playerGuid)) /* 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.vehicles.AccessPermissionGroup
import net.psforever.objects.vital.InGameHistory 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.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.base.message.{SendResponse, SetEmpire}
import net.psforever.services.vehicle.VehicleAction import net.psforever.services.vehicle.VehicleAction
import net.psforever.types.{BailType, ChatMessageType, DriveState, PlanetSideGUID, Vector3} 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 //the player will fall to the ground and is perfectly vulnerable in this state
//additionally, our player must exist in the current zone //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 //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( events ! BundledEnvelope(
MessageEnvelope(player.Name,
SendResponse(Seq(
PlayerStasisMessage(pguid), PlayerStasisMessage(pguid),
PlayerStateShiftMessage(ShiftState(unk=0, obj.Position, obj.Orientation.z, vel=None)) PlayerStateShiftMessage(ShiftState(unk=0, obj.Position, obj.Orientation.z, vel=None))
))) ))
events ! MessageEnvelope( ),
continent.id, MessageEnvelope(continent.id, pguid,
pguid, SendResponse(GenericObjectActionMessage(pguid, code=9)) /* conceal the player */
SendResponse(GenericObjectActionMessage(pguid, code=9)) //conceal the player )
) )
sessionLogic.keepAliveFunc = sessionLogic.zoning.NormalKeepAlive 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.serverobject.terminals.implant.ImplantTerminalMech
import net.psforever.objects.vital.InGameHistory import net.psforever.objects.vital.InGameHistory
import net.psforever.packet.game.{DelayedPathMountMsg, DismountVehicleCargoMsg, DismountVehicleMsg, GenericObjectActionMessage, MountVehicleCargoMsg, MountVehicleMsg, ObjectDetachMessage, PlayerStasisMessage, PlayerStateShiftMessage, ShiftState} 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.base.message.SendResponse
import net.psforever.services.vehicle.VehicleAction 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 //the player will fall to the ground and is perfectly vulnerable in this state
//additionally, our player must exist in the current zone //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 //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( events ! BundledEnvelope(
MessageEnvelope(player.Name,
SendResponse(Seq(
PlayerStasisMessage(pguid), PlayerStasisMessage(pguid),
PlayerStateShiftMessage(ShiftState(unk=0, obj.Position, obj.Orientation.z, vel=None)) PlayerStateShiftMessage(ShiftState(unk=0, obj.Position, obj.Orientation.z, vel=None))
))) ))
events ! MessageEnvelope( ),
continent.id, MessageEnvelope(continent.id, pguid,
pguid, SendResponse(GenericObjectActionMessage(pguid, code=9)) /* conceal the player */
SendResponse(GenericObjectActionMessage(pguid, code=9)) //conceal the player )
) )
context.self ! SessionActor.SetMode(NormalMode) context.self ! SessionActor.SetMode(NormalMode)
sessionLogic.keepAliveFunc = sessionLogic.zoning.NormalKeepAlive 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.blockmap.BlockMapEntity
import net.psforever.objects.zones.exp.ToDatabase import net.psforever.objects.zones.exp.ToDatabase
import net.psforever.services.avatar.support.GroundEnvelope 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.message.{ObjectDelete, PlanetsideAttribute, SendResponse}
import net.psforever.services.base.support.RemoverActor import net.psforever.services.base.support.RemoverActor
import net.psforever.services.local.support.{CaptureEnvelope, HackCaptureActor} import net.psforever.services.local.support.{CaptureEnvelope, HackCaptureActor}
@ -201,26 +201,26 @@ class GeneralOperations(
val guid = player.GUID val guid = player.GUID
val zone = player.Zone val zone = player.Zone
val events = zone.LocalEvents 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 //todo better way to collect csr players while utilizing the aforementioned benefit of localSector
val position = player.Position val position = player.Position
val rangeSq = { val rangeSq = {
val range = math.sqrt(2 * math.pow(sessionLogic.localSector.rangeX.toDouble, 2)) val range = math.sqrt(2 * math.pow(sessionLogic.localSector.rangeX.toDouble, 2))
range * range 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 .AllPlayers
.filter { p => !p.allowInteraction && p.GUID != guid && Vector3.DistanceSquared(p.Position, position) < rangeSq } .filter { p =>
.foreach { p => !p.allowInteraction && p.GUID != guid && !localRecipients.contains(p.Name) && Vector3.DistanceSquared(p.Position, position) < rangeSq
events ! MessageEnvelope(p.Name, msg)
} }
.map(p => MessageEnvelope(p.Name, msg))
events ! BundledEnvelope(localRecipientMessages ++ otherRecipientMessages)
} }
def handleDropItem(pkt: DropItemMessage): GeneralOperations.ItemDropState.Behavior = { def handleDropItem(pkt: DropItemMessage): GeneralOperations.ItemDropState.Behavior = {
@ -1476,23 +1476,21 @@ class GeneralOperations(
val events = continent.AvatarEvents val events = continent.AvatarEvents
val zoneid = continent.id val zoneid = continent.id
val destinationPosition = dest.Position 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 player.Position = destinationPosition
events ! MessageEnvelope(zoneid, pguid, AvatarAction.LoadPlayer( 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, player.Definition.ObjectId,
pguid, pguid,
player.Definition.Packet.ConstructorData(player).get, player.Definition.Packet.ConstructorData(player).get,
None None
)) )),
useRouterTelepadEffect(pguid, sguid, dguid) MessageEnvelope(zoneid, pguid, LocalAction.RouterTelepadTransport(pguid, sguid, dguid))
events ! MessageEnvelope(
continent.id,
pguid,
LocalAction.RouterTelepadTransport(pguid, sguid, dguid)
) )
useRouterTelepadEffect(pguid, sguid, dguid)
sessionLogic.zoning.spawn.ShiftPosition = destinationPosition sessionLogic.zoning.spawn.ShiftPosition = destinationPosition
player.LogActivity(TelepadUseActivity(VehicleSource(router), DeployableSource(remoteTelepad), PlayerSource(player))) player.LogActivity(TelepadUseActivity(VehicleSource(router), DeployableSource(remoteTelepad), PlayerSource(player)))
} else { } 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.OutfitMembershipResponse.PacketType.CreateResponse
import net.psforever.packet.game._ import net.psforever.packet.game._
import net.psforever.services.avatar.AvatarAction 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.services.base.message.{PlanetsideAttribute, SendResponse}
import net.psforever.services.chat.OutfitChannel import net.psforever.services.chat.OutfitChannel
import net.psforever.types.ChatMessageType import net.psforever.types.ChatMessageType
import net.psforever.util.Config import net.psforever.util.Config
@ -50,63 +50,62 @@ object SessionOutfitHandlers {
import scala.concurrent.Future import scala.concurrent.Future
def HandleOutfitForm(outfitName: String, player: Player, session: SessionData): Unit = { 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) val cleanedName = sanitizeOutfitName(outfitName)
cleanedName match { cleanedName match {
case Some(validName) => case Some(validName) =>
ctx.run(findOutfitByName(validName)).flatMap { ctx.run(findOutfitByName(validName)).flatMap {
case existing if existing.nonEmpty => case existing if existing.nonEmpty =>
PlayerControl.sendResponse(player.Zone, player.Name, PlayerControl.sendResponse(zone, pname,
ChatMsg(ChatMessageType.UNK_227, "@OutfitErrorNameAlreadyTaken")) ChatMsg(ChatMessageType.UNK_227, "@OutfitErrorNameAlreadyTaken")
)
Future.successful(()) Future.successful(())
case _ => case _ =>
createNewOutfit(validName, player.Faction.id, player.CharId).map { outfit => createNewOutfit(validName, player.Faction.id, charid).map { outfit =>
val seconds: Long = val outfitId = outfit.id
outfit.created.atZone(ZoneId.systemDefault()).toInstant.toEpochMilli / 1000 val outfitName = outfit.name
val seconds: Long = outfit.created.atZone(ZoneId.systemDefault()).toInstant.toEpochMilli / 1000
PlayerControl.sendResponse(player.Zone, player.Name, player.outfit_id = outfitId
OutfitEvent(outfit.id, Update( player.outfit_name = outfitName
zone.AvatarEvents ! BundledEnvelope(
MessageEnvelope(pname, SendResponse(List(
OutfitEvent(outfitId, Update(
OutfitInfo( OutfitInfo(
outfit.name, 0, 0, 1, outfitName, 0, 0, 1,
OutfitRankNames("", "", "", "", "", "", "", ""), OutfitRankNames("", "", "", "", "", "", "", ""),
"", "",
14, unk11 = true, 0, seconds, 0, 0, 0)))) 14, unk11 = true, 0, seconds, 0, 0, 0)
)),
PlayerControl.sendResponse(player.Zone, player.Name, OutfitMemberUpdate(outfitId, charid, 7, flag = true),
OutfitMemberUpdate(outfit.id, player.CharId, 7, flag = true)) ChatMsg(ChatMessageType.UNK_227, "@OutfitCreateSuccess"),
OutfitMembershipResponse(CreateResponse, 0, 0, charid, 0, "", "", flag = true),
PlayerControl.sendResponse(player.Zone, player.Name, ))),
ChatMsg(ChatMessageType.UNK_227, "@OutfitCreateSuccess")) MessageEnvelope(
zoneid,
PlayerControl.sendResponse(player.Zone, player.Name, PlanetsideAttribute(player.GUID, 39, outfitId)
OutfitMembershipResponse(CreateResponse, 0, 0, player.CharId, 0, "", "", flag = true)) ),
MessageEnvelope(
player.outfit_id = outfit.id zoneid,
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, player.GUID,
AvatarAction.PlanetsideStringAttribute(0, outfit.name) AvatarAction.PlanetsideStringAttribute(0, outfitName)
) )
)
session.chat.JoinChannel(OutfitChannel(player.outfit_id)) session.chat.JoinChannel(OutfitChannel(outfitId))
} }
.recover { case e => .recover { case e =>
e.printStackTrace() e.printStackTrace()
PlayerControl.sendResponse(player.Zone, player.Name, PlayerControl.sendResponse(zone, pname,
ChatMsg(ChatMessageType.UNK_227, "@OutfitCreateFailure")) ChatMsg(ChatMessageType.UNK_227, "@OutfitCreateFailure")
)
} }
} }
case None => case None =>
PlayerControl.sendResponse(player.Zone, player.Name, PlayerControl.sendResponse(zone, pname, ChatMsg(ChatMessageType.UNK_227, "@OutfitCreateFailure"))
ChatMsg(ChatMessageType.UNK_227, "@OutfitCreateFailure"))
} }
} }
@ -127,74 +126,80 @@ object SessionOutfitHandlers {
} }
def HandleOutfitInviteAccept(invited: Player, session: SessionData): Unit = { 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) => case Some(outfitInvite) =>
val fromName = outfitInvite.sentFrom.Name
val fromCharId = outfitInvite.sentFrom.CharId
val fromZone = outfitInvite.sentFrom.Zone
val outfitId = outfitInvite.sentFrom.outfit_id val outfitId = outfitInvite.sentFrom.outfit_id
(for { (for {
_ <- addMemberToOutfit(outfitId, invited.CharId) _ <- addMemberToOutfit(outfitId, toCharId)
outfitOpt <- ctx.run(getOutfitById(outfitId)).map(_.headOption) outfitOpt <- ctx.run(getOutfitById(outfitId)).map(_.headOption)
memberCount <- ctx.run(getOutfitMemberCount(outfitId)) memberCount <- ctx.run(getOutfitMemberCount(outfitId))
points <- ctx.run(getOutfitPoints(outfitId)).map(_.headOption.map(_.points).getOrElse(0L)) points <- ctx.run(getOutfitPoints(outfitId)).map(_.headOption.map(_.points).getOrElse(0L))
} yield (outfitOpt, memberCount, points)) } yield (outfitOpt, memberCount, points))
.map { .map {
case (Some(outfit), memberCount, points) => case (Some(outfit), memberCount, points) =>
val outfitName = outfit.name
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 seconds: Long = outfit.created.atZone(ZoneId.systemDefault()).toInstant.toEpochMilli / 1000 val seconds: Long = outfit.created.atZone(ZoneId.systemDefault()).toInstant.toEpochMilli / 1000
PlayerControl.sendResponse(invited.Zone, invited.Name, 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
)
)
)))
)
toZone.AvatarEvents ! BundledEnvelope(
MessageEnvelope(toName, SendResponse(List(
OutfitMembershipResponse(
OutfitMembershipResponse.PacketType.InviteAccepted, 0, 0,
toCharId, fromCharId, toName, outfitName, flag = true
),
OutfitEvent(outfitId, Initial(OutfitInfo( OutfitEvent(outfitId, Initial(OutfitInfo(
outfit.name, points, points, memberCount, outfitName, points, points, memberCount,
OutfitRankNames("", "", "", "", "", "", "", ""), OutfitRankNames("", "", "", "", "", "", "", ""),
outfit.motd.getOrElse(""), outfit.motd.getOrElse(""),
14, unk11 = true, 0, seconds, 0, 0, 0)))) 14, unk11 = true, 0, seconds, 0, 0, 0
))),
PlayerControl.sendResponse(invited.Zone, invited.Name, OutfitMemberUpdate(outfitId, toCharId, 0, flag=true)
OutfitMemberUpdate(outfit.id, invited.CharId, 0, flag=true)) ))),
MessageEnvelope(
OutfitInviteManager.removeOutfitInvite(invited.CharId) toZoneId,
PlanetsideAttribute(toGuid, 39, outfitId)
session.chat.JoinChannel(OutfitChannel(outfit.id)) ),
invited.outfit_id = outfit.id MessageEnvelope(
invited.outfit_name = outfit.name toZoneId,
toGuid,
invited.Zone.AvatarEvents ! MessageEnvelope( AvatarAction.PlanetsideStringAttribute(0, outfitName)
invited.Zone.id,
PlanetsideAttribute(invited.GUID, 39, outfit.id)
) )
invited.Zone.AvatarEvents ! MessageEnvelope(
invited.Zone.id,
invited.GUID,
AvatarAction.PlanetsideStringAttribute(0, outfit.name)
) )
case (None, _, _) => OutfitInviteManager.removeOutfitInvite(toCharId)
session.chat.JoinChannel(OutfitChannel(outfitId))
PlayerControl.sendResponse(invited.Zone, invited.Name, invited.outfit_id = outfitId
ChatMsg(ChatMessageType.UNK_227, "Failed to join outfit")) invited.outfit_name = outfitName
case (None, _, _) => ()
PlayerControl.sendResponse(toZone, toName,
ChatMsg(ChatMessageType.UNK_227, "Failed to join outfit")
)
} }
.recover { case _ => .recover { case _ =>
PlayerControl.sendResponse(invited.Zone, invited.Name, PlayerControl.sendResponse(toZone, toName,
ChatMsg(ChatMessageType.UNK_227, "Failed to join outfit")) ChatMsg(ChatMessageType.UNK_227, "Failed to join outfit")
)
} }
case None => case None => ()
} }
} }
@ -218,39 +223,37 @@ object SessionOutfitHandlers {
} }
def HandleOutfitKick(zones: Seq[Zone], kickedId: Long, kickedBy: Player, session: SessionData): Unit = { 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 same id, player has left the outfit by their own choice
if (kickedId == kickedBy.CharId) { if (kickedId == kickedBy.CharId) {
// store outfit_id since it will be nulled soon // store outfit_id since it will be nulled soon
val outfit_id = kickedBy.outfit_id
removeMemberFromOutfit(outfit_id, kickedId).map { removeMemberFromOutfit(outfit_id, kickedId).map {
case (deleted, _) => case (deleted, _) =>
if (deleted > 0) { if (deleted > 0) {
kickedBy.Zone.AvatarEvents ! BundledEnvelope(
PlayerControl.sendResponse(kickedBy.Zone, kickedBy.Name, MessageEnvelope(kickedBy.Name, SendResponse(OutfitEvent(outfit_id, Leaving()))),
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)) session.chat.LeaveChannel(OutfitChannel(outfit_id))
kickedBy.outfit_name = "" kickedBy.outfit_name = ""
kickedBy.outfit_id = 0 kickedBy.outfit_id = 0
zones.filter(z => z.AllPlayers.nonEmpty).flatMap(_.AllPlayers) zones
.filter(p => p.outfit_id == outfit_id).foreach(outfitMember => .filter(z => z.AllPlayers.nonEmpty)
.flatMap(_.AllPlayers)
.filter(p => p.outfit_id == outfit_id)
.foreach(outfitMember =>
PlayerControl.sendResponse(outfitMember.Zone, outfitMember.Name, PlayerControl.sendResponse(outfitMember.Zone, outfitMember.Name,
OutfitMemberEvent(outfit_id, kickedId, OutfitMemberEventAction.Kicked())) 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, "")
) )
} }
}.recover { case e => }.recover { case e =>
@ -258,42 +261,38 @@ object SessionOutfitHandlers {
} }
} }
else { else {
removeMemberFromOutfit(kickedBy.outfit_id, kickedId).map { removeMemberFromOutfit(outfit_id, kickedId).map {
case (deleted, _) => case (deleted, _) =>
if (deleted > 0) { if (deleted > 0) {
findPlayerByIdForOutfitAction(zones, kickedId, kickedBy).foreach { kicked => findPlayerByIdForOutfitAction(zones, kickedId, kickedBy).foreach { kicked =>
kicked.Zone.AvatarEvents ! BundledEnvelope(
PlayerControl.sendResponse(kicked.Zone, kicked.Name, MessageEnvelope(kicked.Name, SendResponse(List(
OutfitEvent(kickedBy.outfit_id, Leaving()) OutfitEvent(outfit_id, Leaving()),
OutfitMembershipResponse(
OutfitMembershipResponse.PacketType.YouGotKicked, 0, 1,
kickedBy.CharId, kicked.CharId, kickedBy.Name, kicked.Name, flag = false
) )
))),
PlayerControl.sendResponse(kicked.Zone, kicked.Name, MessageEnvelope(kicked.Zone.id,
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) PlanetsideAttribute(kicked.GUID, 39, 0)
) ),
MessageEnvelope(
kicked.Zone.AvatarEvents ! MessageEnvelope(
kicked.Zone.id, kicked.Zone.id,
kicked.GUID, kicked.GUID,
AvatarAction.PlanetsideStringAttribute(0, "") AvatarAction.PlanetsideStringAttribute(0, "")
),
MessageEnvelope(kicked.Name,
AvatarAction.RemoveFromOutfitChat(outfit_id)
),
MessageEnvelope(kicked.Name, SendResponse(
OutfitMemberEvent(outfit_id, kickedId, OutfitMemberEventAction.Kicked())
))
) )
kicked.Zone.AvatarEvents ! MessageEnvelope(
kicked.Name, AvatarAction.RemoveFromOutfitChat(kickedBy.outfit_id))
kicked.outfit_id = 0 kicked.outfit_id = 0
kicked.outfit_name = "" kicked.outfit_name = ""
PlayerControl.sendResponse(kicked.Zone, kicked.Name,
OutfitMemberEvent(kickedBy.outfit_id, kickedId, OutfitMemberEventAction.Kicked()))
} }
val avatarName: Future[Option[String]] = val avatarName: Future[Option[String]] =
ctx.run( ctx.run(quote { query[Avatar].filter(_.id == lift(kickedId)).map(_.name) }).map(_.headOption)
quote { query[Avatar].filter(_.id == lift(kickedId)).map(_.name) }
).map(_.headOption)
avatarName.foreach { avatarName.foreach {
case Some(name) => PlayerControl.sendResponse(kickedBy.Zone, kickedBy.Name, case Some(name) => PlayerControl.sendResponse(kickedBy.Zone, kickedBy.Name,
@ -302,10 +301,14 @@ object SessionOutfitHandlers {
case None => PlayerControl.sendResponse(kickedBy.Zone, kickedBy.Name, case None => PlayerControl.sendResponse(kickedBy.Zone, kickedBy.Name,
OutfitMembershipResponse(OutfitMembershipResponse.PacketType.YouKicked, 0, 1, kickedBy.CharId, kickedId, "NameNotFound", "", flag = true)) OutfitMembershipResponse(OutfitMembershipResponse.PacketType.YouKicked, 0, 1, kickedBy.CharId, kickedId, "NameNotFound", "", flag = true))
} }
zones.filter(z => z.AllPlayers.nonEmpty).flatMap(_.AllPlayers) zones
.filter(p => p.outfit_id == kickedBy.outfit_id).foreach(outfitMember => .filter(z => z.AllPlayers.nonEmpty)
.flatMap(_.AllPlayers)
.filter(p => p.outfit_id == kickedBy.outfit_id)
.foreach(outfitMember =>
PlayerControl.sendResponse(outfitMember.Zone, outfitMember.Name, PlayerControl.sendResponse(outfitMember.Zone, outfitMember.Name,
OutfitMemberEvent(kickedBy.outfit_id, kickedId, OutfitMemberEventAction.Kicked())) OutfitMemberEvent(kickedBy.outfit_id, kickedId, OutfitMemberEventAction.Kicked())
)
) )
// this needs to be the kicked player // this needs to be the kicked player
// session.chat.LeaveChannel(OutfitChannel(kickedBy.outfit_id)) // 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 = { def HandleOutfitPromote(zones: Seq[Zone], promotedId: Long, newRank: Int, promoter: Player): Unit = {
val outfit_id = promoter.outfit_id val outfit_id = promoter.outfit_id
findPlayerByIdForOutfitAction(zones, promotedId, promoter).foreach { promoted => findPlayerByIdForOutfitAction(zones, promotedId, promoter).foreach { promoted =>
if (newRank == 7) { if (newRank == 7) {
// demote owner to rank 6 // demote owner to rank 6
// promote promoted to rank 7 // promote promoted to rank 7
// update outfit // update outfit
updateOutfitOwner(outfit_id, promoter.avatar.id, promoted.avatar.id) updateOutfitOwner(outfit_id, promoter.avatar.id, promoted.avatar.id)
// TODO: does every member get the notification like this? // TODO: does every member get the notification like this?
getOutfitMemberPoints(outfit_id, promoter.avatar.id).map { getOutfitMemberPoints(outfit_id, promoter.avatar.id).map {
owner_points => owner_points =>
@ -346,7 +344,6 @@ object SessionOutfitHandlers {
}) })
}) })
} }
// update promoter rank // update promoter rank
PlayerControl.sendResponse( PlayerControl.sendResponse(
promoter.Zone, promoter.Name, promoter.Zone, promoter.Name,
@ -360,17 +357,19 @@ object SessionOutfitHandlers {
// TODO: does every member get the notification like this? // TODO: does every member get the notification like this?
getOutfitMemberPoints(outfit_id, promoted.avatar.id).map { getOutfitMemberPoints(outfit_id, promoted.avatar.id).map {
member_points => member_points =>
zones.foreach { zone =>
// tell everyone about the new rank of the promoted member // tell everyone about the new rank of the promoted member
zones.foreach(zone => { val messages = zone.AllPlayers
zone.AllPlayers
.filter(_.outfit_id == outfit_id) .filter(_.outfit_id == outfit_id)
.foreach(player => { .map { player =>
PlayerControl.sendResponse( MessageEnvelope(player.Name, SendResponse(
zone, player.Name,
OutfitMemberEvent(outfit_id, promoted.avatar.id, 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 // update promoted rank
@ -386,7 +385,6 @@ object SessionOutfitHandlers {
memberCount <- ctx.run(query[Outfitmember].filter(_.outfit_id == lift(outfitId)).size) memberCount <- ctx.run(query[Outfitmember].filter(_.outfit_id == lift(outfitId)).size)
pointsTotal <- ctx.run(querySchema[OutfitpointMv]("outfitpoint_mv").filter(_.outfit_id == lift(outfitId))) pointsTotal <- ctx.run(querySchema[OutfitpointMv]("outfitpoint_mv").filter(_.outfit_id == lift(outfitId)))
} yield (outfitOpt, memberCount, pointsTotal.headOption.map(_.points).getOrElse(0L)) } yield (outfitOpt, memberCount, pointsTotal.headOption.map(_.points).getOrElse(0L))
val membersF = ctx.run(getOutfitMembersWithDetails(outfitId)) val membersF = ctx.run(getOutfitMembersWithDetails(outfitId))
for { for {
@ -395,9 +393,7 @@ object SessionOutfitHandlers {
} yield { } yield {
outfitOpt.foreach { outfit => outfitOpt.foreach { outfit =>
val seconds: Long = outfit.created.atZone(ZoneId.systemDefault()).toInstant.toEpochMilli / 1000 val seconds: Long = outfit.created.atZone(ZoneId.systemDefault()).toInstant.toEpochMilli / 1000
val outfitEventInitial = OutfitEvent(outfit.id, Initial(OutfitInfo(
PlayerControl.sendResponse(player.Zone, player.Name,
OutfitEvent(outfit.id, Initial(OutfitInfo(
outfit.name, outfit.name,
totalPoints, totalPoints,
totalPoints, totalPoints,
@ -413,25 +409,26 @@ object SessionOutfitHandlers {
outfit.rank7.getOrElse(""), outfit.rank7.getOrElse(""),
), ),
outfit.motd.getOrElse(""), outfit.motd.getOrElse(""),
14, unk11 = true, 0, seconds, 0, 0, 0)))) 14, unk11 = true, 0, seconds, 0, 0, 0))
)
members.foreach { case (avatarId, avatarName, points, rank, login) => val memberEventList = members.map { case (avatarId, avatarName, points, rank, login) =>
val lastLogin = findPlayerByIdForOutfitAction(zones, avatarId, player) match { val lastLogin = findPlayerByIdForOutfitAction(zones, avatarId, player) match {
case Some(_) => 0L case Some(_) => 0L
case None if player.Name == avatarName => 0L case None if player.Name == avatarName => 0L
case None => (System.currentTimeMillis() - login.atZone(ZoneId.systemDefault()).toInstant.toEpochMilli) / 1000 case None => (System.currentTimeMillis() - login.atZone(ZoneId.systemDefault()).toInstant.toEpochMilli) / 1000
} }
PlayerControl.sendResponse(player.Zone, player.Name,
OutfitMemberEvent(outfit.id, avatarId, OutfitMemberEvent(outfit.id, avatarId,
OutfitMemberEventAction.Update( OutfitMemberEventAction.Update(
avatarName, avatarName,
rank, rank,
points, points,
lastLogin, lastLogin,
OutfitMemberEventAction.PacketType.Padding, 0))) OutfitMemberEventAction.PacketType.Padding, 0)
)
} }
PlayerControl.sendResponse(player.Zone, player.Name, player.Zone.AvatarEvents ! MessageEnvelope(player.Name, SendResponse(
OutfitEvent(outfit.id, Unk1())) outfitEventInitial +: memberEventList :+ OutfitEvent(outfit.id, Unk1())
))
} }
} }
} }
@ -442,16 +439,13 @@ object SessionOutfitHandlers {
futureResult.onComplete { futureResult.onComplete {
case Success(rows) => case Success(rows) =>
rows.foreach { case (outfitId, points, name, leaderName, memberCount) => player.Zone.AvatarEvents ! MessageEnvelope(player.Name, SendResponse(
PlayerControl.sendResponse(player.Zone, player.Name, rows.map { case (outfitId, points, name, leaderName, memberCount) =>
OutfitListEvent( OutfitListEvent(
OutfitListEventAction.ListElementOutfit( OutfitListEventAction.ListElementOutfit(outfitId, points, memberCount, name, leaderName)
outfitId, )
points,
memberCount,
name,
leaderName)))
} }
))
case Failure(_) => case Failure(_) =>
PlayerControl.sendResponse(player.Zone, player.Name, PlayerControl.sendResponse(player.Zone, player.Name,
@ -461,9 +455,7 @@ object SessionOutfitHandlers {
} }
def HandleOutfitMotd(zones: Seq[Zone], message: String, player: Player): Unit = { def HandleOutfitMotd(zones: Seq[Zone], message: String, player: Player): Unit = {
val outfit_id = player.outfit_id val outfit_id = player.outfit_id
val outfitDetails = for { val outfitDetails = for {
_ <- updateOutfitMotd(outfit_id, message) _ <- updateOutfitMotd(outfit_id, message)
outfitOpt <- ctx.run(getOutfitById(outfit_id)).map(_.headOption) outfitOpt <- ctx.run(getOutfitById(outfit_id)).map(_.headOption)
@ -475,9 +467,8 @@ object SessionOutfitHandlers {
(outfitOpt, memberCount, totalPoints) <- outfitDetails (outfitOpt, memberCount, totalPoints) <- outfitDetails
} yield { } yield {
outfitOpt.foreach { outfit => outfitOpt.foreach { outfit =>
// send to all online players in outfit // send to all online players in outfit
val outfit_event = OutfitEvent( val outfit_event = SendResponse(OutfitEvent(
outfit_id, outfit_id,
Update( Update(
OutfitInfo( OutfitInfo(
@ -505,19 +496,15 @@ object SessionOutfitHandlers {
unk25 = 0 unk25 = 0
) )
) )
) ))
zones.foreach(zone => { zones.foreach { zone =>
zone.AvatarEvents ! BundledEnvelope(
zone.AllPlayers zone.AllPlayers
.filter(_.outfit_id == outfit_id) .filter { p => p.outfit_id == outfit_id && p.outfit_window_open }
.filter(_.outfit_window_open) .map(p => MessageEnvelope(p.Name, outfit_event))
.foreach(player => {
PlayerControl.sendResponse(
zone, player.Name,
outfit_event
) )
}) }
})
} }
} }
@ -526,9 +513,7 @@ object SessionOutfitHandlers {
} }
def HandleOutfitRank(zones: Seq[Zone], list: List[Option[String]], player: Player): Unit = { def HandleOutfitRank(zones: Seq[Zone], list: List[Option[String]], player: Player): Unit = {
val outfit_id = player.outfit_id val outfit_id = player.outfit_id
val outfitDetails = for { val outfitDetails = for {
_ <- updateOutfitRanks(outfit_id, list) _ <- updateOutfitRanks(outfit_id, list)
outfitOpt <- ctx.run(getOutfitById(outfit_id)).map(_.headOption) outfitOpt <- ctx.run(getOutfitById(outfit_id)).map(_.headOption)
@ -540,9 +525,8 @@ object SessionOutfitHandlers {
(outfitOpt, memberCount, totalPoints) <- outfitDetails (outfitOpt, memberCount, totalPoints) <- outfitDetails
} yield { } yield {
outfitOpt.foreach { outfit => outfitOpt.foreach { outfit =>
// send to all online players in outfit with window open // send to all online players in outfit with window open
val outfit_event = OutfitEvent( val outfit_event = SendResponse(OutfitEvent(
outfit_id, outfit_id,
Update( Update(
OutfitInfo( OutfitInfo(
@ -570,19 +554,15 @@ object SessionOutfitHandlers {
unk25 = 0 unk25 = 0
) )
) )
) ))
zones.foreach(zone => { zones.foreach { zone =>
zone.AvatarEvents ! BundledEnvelope(
zone.AllPlayers zone.AllPlayers
.filter(_.outfit_id == outfit_id) .filter { p => p.outfit_id == outfit_id && p.outfit_window_open }
.filter(_.outfit_window_open) .map(p => MessageEnvelope(p.Name, outfit_event))
.foreach(player => {
PlayerControl.sendResponse(
zone, player.Name,
outfit_event
) )
}) }
})
} }
} }
} }
@ -618,33 +598,33 @@ object SessionOutfitHandlers {
.map { .map {
case (Some(outfit), memberCount, points) => case (Some(outfit), memberCount, points) =>
val seconds: Long = outfit.created.atZone(ZoneId.systemDefault()).toInstant.toEpochMilli / 1000 val seconds: Long = outfit.created.atZone(ZoneId.systemDefault()).toInstant.toEpochMilli / 1000
player.Zone.AvatarEvents ! BundledEnvelope(
PlayerControl.sendResponse(player.Zone, player.Name, MessageEnvelope(player.Name, SendResponse(List(
OutfitEvent(outfitId, Update(OutfitInfo( OutfitEvent(outfitId, Update(OutfitInfo(
outfit.name, points, points, memberCount, outfit.name, points, points, memberCount,
OutfitRankNames(outfit.rank0.getOrElse(""), outfit.rank1.getOrElse(""), outfit.rank2.getOrElse(""), OutfitRankNames(
outfit.rank0.getOrElse(""), outfit.rank1.getOrElse(""), outfit.rank2.getOrElse(""),
outfit.rank3.getOrElse(""), outfit.rank4.getOrElse(""), outfit.rank5.getOrElse(""), outfit.rank3.getOrElse(""), outfit.rank4.getOrElse(""), outfit.rank5.getOrElse(""),
outfit.rank6.getOrElse(""), outfit.rank7.getOrElse("")), outfit.rank6.getOrElse(""), outfit.rank7.getOrElse("")
),
outfit.motd.getOrElse(""), outfit.motd.getOrElse(""),
14, unk11 = true, 0, seconds, 0, 0, 0)))) 14, unk11 = true, 0, seconds, 0, 0, 0
))),
PlayerControl.sendResponse(player.Zone, player.Name, OutfitMemberUpdate(outfit.id, player.CharId, membership.rank, flag = true)
OutfitMemberUpdate(outfit.id, player.CharId, membership.rank, flag = true)) ))),
MessageEnvelope(
session.chat.JoinChannel(OutfitChannel(outfit.id))
player.outfit_id = outfit.id
player.outfit_name = outfit.name
player.Zone.AvatarEvents ! MessageEnvelope(
player.Zone.id, player.Zone.id,
PlanetsideAttribute(player.GUID, 39, outfit.id) PlanetsideAttribute(player.GUID, 39, outfit.id)
) ),
MessageEnvelope(
player.Zone.AvatarEvents ! MessageEnvelope(
player.Zone.id, player.Zone.id,
player.GUID, player.GUID,
AvatarAction.PlanetsideStringAttribute(0, outfit.name) AvatarAction.PlanetsideStringAttribute(0, outfit.name)
) )
)
session.chat.JoinChannel(OutfitChannel(outfit.id))
player.outfit_id = outfit.id
player.outfit_name = outfit.name
case (None, _, _) => case (None, _, _) =>
PlayerControl.sendResponse(player.Zone, player.Name, PlayerControl.sendResponse(player.Zone, player.Name,
@ -876,7 +856,7 @@ object SessionOutfitHandlers {
query[Outfit] query[Outfit]
.filter(_.id == lift(outfit_id)) .filter(_.id == lift(outfit_id))
.update( .update(
_.rank0 -> lift(colorized(0)), _.rank0 -> lift(colorized.head),
_.rank1 -> lift(colorized(1)), _.rank1 -> lift(colorized(1)),
_.rank2 -> lift(colorized(2)), _.rank2 -> lift(colorized(2)),
_.rank3 -> lift(colorized(3)), _.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.GenericAction.FirstPersonViewWithEffect
import net.psforever.packet.game.{CampaignStatistic, ChangeFireStateMessage_Start, CloudInfo, GenericActionMessage, GenericObjectActionEnum, HackState7, MailMessage, ObjectDetectedMessage, SessionStatistic, StormInfo, TrainingZoneMessage, TriggeredSound, WeatherMessage} 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.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.base.message.{GenericObjectAction, ObjectDelete, PlanetsideAttribute, SendResponse}
import net.psforever.services.chat.DefaultChannel import net.psforever.services.chat.DefaultChannel
@ -4005,21 +4005,20 @@ class ZoningOperations(
} }
GoToDeploymentMap() GoToDeploymentMap()
val pZone = player.Zone val pZone = player.Zone
val msg = GenericObjectAction(player.GUID, GenericObjectActionEnum.PlayerDeconstructs.id)
sendResponse(GenericActionMessage(FirstPersonViewWithEffect)) sendResponse(GenericActionMessage(FirstPersonViewWithEffect))
pZone.blockMap.sector(player).livePlayerList.collect { case t if t.GUID != player.GUID => val (localMessageRecipients, localMesages) = pZone.blockMap.sector(player).livePlayerList
pZone.LocalEvents ! MessageEnvelope( .collect {
t.Name, case t if t.GUID != player.GUID =>
t.GUID, (t.Name, MessageEnvelope(t.Name, msg))
GenericObjectAction(player.GUID, GenericObjectActionEnum.PlayerDeconstructs.id)
)
} }
pZone.AllPlayers.collect { case t if t.GUID != player.GUID && !t.allowInteraction => .unzip
pZone.LocalEvents ! MessageEnvelope( val otherMessages: Seq[MessageEnvelope] = pZone.AllPlayers
t.Name, .collect {
t.GUID, case t if t.GUID != player.GUID && !t.allowInteraction && !localMessageRecipients.contains(t.Name) =>
GenericObjectAction(player.GUID, GenericObjectActionEnum.PlayerDeconstructs.id) MessageEnvelope(t.Name, msg)
)
} }
pZone.LocalEvents ! BundledEnvelope(localMesages ++ otherMessages)
} }
def stopDeconstructing(): Unit = { def stopDeconstructing(): Unit = {

View file

@ -293,11 +293,12 @@ object DeployableBehavior {
MessageEnvelope(toFaction.toString, LocalAction.DeployableMapIcon(DeploymentAction.Build, info)) MessageEnvelope(toFaction.toString, LocalAction.DeployableMapIcon(DeploymentAction.Build, info))
) )
//remove deployable from original owner's toolbox and UI counter //remove deployable from original owner's toolbox and UI counter
zone.AllPlayers.filter(p => obj.OriginalOwnerName.contains(p.Name)) localEvents ! BundledEnvelope(zone.AllPlayers
.foreach { originalOwner => .filter(p => obj.OriginalOwnerName.contains(p.Name))
.map { originalOwner =>
originalOwner.avatar.deployables.Remove(obj) 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.objects.vital.interaction.{DamageInteraction, DamageResult}
import net.psforever.packet.game.DamageWithPositionMessage import net.psforever.packet.game.DamageWithPositionMessage
import net.psforever.services.avatar.AvatarAction 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} import net.psforever.services.base.message.{HintsAtAttacker, SendResponse}
/** /**
@ -37,6 +37,7 @@ object DamageableMountable {
val zone = target.Zone val zone = target.Zone
val events = zone.AvatarEvents val events = zone.AvatarEvents
val occupants = target.Seats.values.toSeq.flatMap { seat => seat.occupants.filter(_.isAlive) } val occupants = target.Seats.values.toSeq.flatMap { seat => seat.occupants.filter(_.isAlive) }
events ! BundledEnvelope(
((cause.adversarial match { ((cause.adversarial match {
case Some(adversarial) => Some(adversarial.attacker) case Some(adversarial) => Some(adversarial.attacker)
case None => None case None => None
@ -59,10 +60,11 @@ object DamageableMountable {
occupants.map { tplayer => (tplayer.Name, Default.GUID0, msg) } occupants.map { tplayer => (tplayer.Name, Default.GUID0, msg) }
case None => case None =>
List.empty List.empty
}).foreach { }).map {
case (channel, filter, msg) => case (channel, filter, msg) =>
events ! MessageEnvelope(channel, filter, msg) MessageEnvelope(channel, filter, msg)
} }
)
} }
/** /**

View file

@ -253,7 +253,7 @@ trait DamageableVehicle
) )
if (obj.Shields > 0) { if (obj.Shields > 0) {
obj.Shields = 0 obj.Shields = 0
zone.VehicleEvents ! MessageEnvelope( events ! MessageEnvelope(
zone.id, zone.id,
PlanetsideAttribute(obj.GUID, obj.Definition.shieldUiAttribute, 0) 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.objects.zones.Zone
import net.psforever.packet.game.DamageWithPositionMessage import net.psforever.packet.game.DamageWithPositionMessage
import net.psforever.types.Vector3 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.message.{ObjectDelete, PlanetsideAttribute, SendResponse}
import net.psforever.services.base.support.SupportActor import net.psforever.services.base.support.SupportActor
import net.psforever.services.vehicle.support.{TurretEnvelope, TurretUpgrader} import net.psforever.services.vehicle.support.{TurretEnvelope, TurretUpgrader}
@ -72,11 +72,12 @@ trait DamageableWeaponTurret
if (announceConfrontation) { if (announceConfrontation) {
if (aggravated) { if (aggravated) {
val msg = SendResponse(DamageWithPositionMessage(damageToHealth, Vector3.Zero)) 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 } .collect { case seat if seat.occupant.nonEmpty => seat.occupant.get.Name }
.foreach { channel => .map { channel =>
events ! MessageEnvelope(channel, msg) MessageEnvelope(channel, msg)
} }
)
} }
else { else {
//activity on map //activity on map
@ -124,14 +125,12 @@ object DamageableWeaponTurret {
val zone = target.Zone val zone = target.Zone
val zoneId = zone.id val zoneId = zone.id
val avatarEvents = zone.AvatarEvents val avatarEvents = zone.AvatarEvents
target.Weapons.values avatarEvents ! BundledEnvelope(target.Weapons.values
.filter { .filter(_.Equipment.nonEmpty)
_.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 { target match {
case turret: WeaponTurret => case turret: WeaponTurret =>
if (turret.Upgrade != TurretUpgrade.None) { 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.vital.prop.DamageWithPosition
import net.psforever.objects.zones.Zone import net.psforever.objects.zones.Zone
import net.psforever.packet.game.ChatMsg 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.base.message.SendResponse
import net.psforever.services.local.LocalAction import net.psforever.services.local.LocalAction
import net.psforever.types.{ChatMessageType, PlanetSideEmpire, PlanetSideGeneratorState, Vector3} import net.psforever.types.{ChatMessageType, PlanetSideEmpire, PlanetSideGeneratorState, Vector3}
@ -143,9 +143,9 @@ object ForceDomeControl {
ChatMessageType.UNK_227, ChatMessageType.UNK_227,
"Expected capitol force dome state change will resume." "Expected capitol force dome state change will resume."
)) ))
building.PlayersInSOI.foreach { player => events ! BundledEnvelope(building.PlayersInSOI.map { player =>
events ! MessageEnvelope(player.Name, message) 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.equipment.EquipmentSlot
import net.psforever.objects.serverobject.turret.WeaponTurret import net.psforever.objects.serverobject.turret.WeaponTurret
import net.psforever.objects.vehicles.MountedWeapons 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 import net.psforever.services.vehicle.VehicleAction
/** /**
@ -41,14 +41,15 @@ object RepairableWeaponTurret {
val zoneId = zone.id val zoneId = zone.id
val tguid = target.GUID val tguid = target.GUID
val events = zone.VehicleEvents val events = zone.VehicleEvents
target.Weapons events ! BundledEnvelope(target.Weapons
.map({ case (index, slot: EquipmentSlot) => (index, slot.Equipment) }) .map({ case (index, slot: EquipmentSlot) => (index, slot.Equipment) })
.collect { .collect {
case (index: Int, Some(tool: Tool)) => case (index: Int, Some(tool: Tool)) =>
events ! MessageEnvelope( MessageEnvelope(
zoneId, zoneId,
VehicleAction.EquipmentInSlot(tguid, index, tool) 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.types.{ExperienceType, PlanetSideEmpire}
import net.psforever.services.Service import net.psforever.services.Service
import net.psforever.services.avatar.AvatarAction 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.services.base.message.PlanetsideAttribute
import net.psforever.util.Config import net.psforever.util.Config
@ -203,12 +203,16 @@ class ResourceSiloControl(resourceSilo: ResourceSilo)
(Config.app.game.experience.sep.ntuSiloDepositReward.toFloat * (Config.app.game.experience.sep.ntuSiloDepositReward.toFloat *
amount * resourceSilo.Definition.ChargeTime.toSeconds.toFloat / resourceSilo.MaxNtuCapacitor amount * resourceSilo.Definition.ChargeTime.toSeconds.toFloat / resourceSilo.MaxNtuCapacitor
).toLong ).toLong
vehicle.Zone.AvatarEvents ! MessageEnvelope( vehicle.Zone.AvatarEvents ! BundledEnvelope(
MessageEnvelope(
owner.name, owner.name,
AvatarAction.AwardBep(owner.charId, deposit, ExperienceType.Normal) 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) 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.avatar.scoring.Kill
import net.psforever.objects.sourcing.UniquePlayer import net.psforever.objects.sourcing.UniquePlayer
import net.psforever.packet.game.GenericObjectActionMessage 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.services.base.message.SendResponse
import net.psforever.types.{PlanetSideEmpire, Vector3} import net.psforever.types.{PlanetSideEmpire, Vector3}
@ -115,9 +115,9 @@ trait FacilityHackParticipation extends ParticipationLogic {
GenericObjectActionMessage(mainTerm, 58) GenericObjectActionMessage(mainTerm, 58)
)) ))
val events = building.Zone.AvatarEvents val events = building.Zone.AvatarEvents
list.foreach { p => events ! BundledEnvelope(list.map { p =>
events ! MessageEnvelope(p.Name, pkts) 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.serverobject.hackable.Hackable
import net.psforever.objects.zones.exp.ToDatabase import net.psforever.objects.zones.exp.ToDatabase
import net.psforever.packet.game.ChatMsg 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.base.message.SendResponse
import scala.collection.mutable import scala.collection.mutable
@ -307,14 +307,15 @@ final case class MajorFacilityHackParticipation(building: Building) extends Faci
events ! MessageEnvelope(hacker.Name, AvatarAction.AwardCep(hackerId, finalCep)) events ! MessageEnvelope(hacker.Name, AvatarAction.AwardCep(hackerId, finalCep))
}*/ }*/
//bystanders (cep if squad leader, bep otherwise) //bystanders (cep if squad leader, bep otherwise)
contributingPlayers events ! BundledEnvelope(contributingPlayers
//.filterNot { _.CharId == hackerId } //.filterNot { _.CharId == hackerId }
.foreach { player => .map { player =>
val charId = player.CharId val charId = player.CharId
val contributionMultiplier = contributionPerPlayerByTime.getOrElse(charId, 1f) val contributionMultiplier = contributionPerPlayerByTime.getOrElse(charId, 1f)
val outputValue = (finalCep * contributionMultiplier).toLong 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) //flag carrier (won't be in soi, but earns cep from capture)
flagCarrier.collect { flagCarrier.collect {
case player if !isResecured => case player if !isResecured =>
@ -440,8 +441,8 @@ object MajorFacilityHackParticipation {
): Unit = { ): Unit = {
val events = building.Zone.LocalEvents val events = building.Zone.LocalEvents
val message = SendResponse(msg) val message = SendResponse(msg)
targets.foreach { player => events ! BundledEnvelope(targets.map { player =>
events ! MessageEnvelope(player.Name, message) 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.sourcing.PlayerSource
import net.psforever.objects.zones.exp.ToDatabase import net.psforever.objects.zones.exp.ToDatabase
import net.psforever.services.avatar.AvatarAction 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.types.{PlanetSideEmpire, Vector3}
import net.psforever.util.Config import net.psforever.util.Config
@ -154,18 +154,19 @@ final case class TowerHackParticipation(building: Building) extends FacilityHack
expType = "cep" expType = "cep"
) )
//bystanders (cep if squad leader, bep otherwise) //bystanders (cep if squad leader, bep otherwise)
soiPlayers events ! BundledEnvelope(soiPlayers
.filterNot(_.CharId == hackerId) .filterNot(_.CharId == hackerId)
.foreach { player => .map { player =>
val charId = player.CharId val charId = player.CharId
val contributionTimeMultiplier = contributionPerPlayerByTime.getOrElse(charId, 0.5f) val contributionTimeMultiplier = contributionPerPlayerByTime.getOrElse(charId, 0.5f)
val contributionDistanceMultiplier = contributionPerPlayerByDistanceFromGoal.getOrElse(charId, 0.5f) val contributionDistanceMultiplier = contributionPerPlayerByDistanceFromGoal.getOrElse(charId, 0.5f)
val outputValue = (finalCep * contributionTimeMultiplier * contributionDistanceMultiplier).toLong val outputValue = (finalCep * contributionTimeMultiplier * contributionDistanceMultiplier).toLong
events ! MessageEnvelope( MessageEnvelope(
player.Name, player.Name,
AvatarAction.FacilityCaptureRewards(buildingId, zoneNumber, outputValue) AvatarAction.FacilityCaptureRewards(buildingId, zoneNumber, outputValue)
) )
} }
)
} else { } else {
//no need to calculate a fancy score //no need to calculate a fancy score
ToDatabase.reportFacilityCaptureInBulk( 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.sourcing.AmenitySource
import net.psforever.objects.vital.interaction.DamageResult import net.psforever.objects.vital.interaction.DamageResult
import net.psforever.packet.game.HackState1 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.base.message.{PlanetsideAttribute, SendResponse}
import net.psforever.services.local.support.{HackClearActor, HackClearEnvelope} import net.psforever.services.local.support.{HackClearActor, HackClearEnvelope}
import org.log4s.Logger import org.log4s.Logger
@ -432,12 +432,12 @@ object ProximityTerminalControl {
val events = unit.Zone.AvatarEvents val events = unit.Zone.AvatarEvents
val channel = target.Name val channel = target.Name
ancient.foreach { case (weapon, slots) => ancient.foreach { case (weapon, slots) =>
slots.foreach { slot => events ! BundledEnvelope(slots.map { slot =>
events ! MessageEnvelope( MessageEnvelope(
channel, channel,
SendResponse(InventoryStateMessage(slot.Box.GUID, weapon.GUID, slot.Box.Capacity)) SendResponse(InventoryStateMessage(slot.Box.GUID, weapon.GUID, slot.Box.Capacity))
) )
} })
} }
!result.flatMap { _._2 }.exists { slot => slot.Magazine < slot.MaxMagazine() } !result.flatMap { _._2 }.exists { slot => slot.Magazine < slot.MaxMagazine() }
} }
@ -457,14 +457,14 @@ object ProximityTerminalControl {
) )
val events = unit.Zone.VehicleEvents val events = unit.Zone.VehicleEvents
val channel = target.Actor.toString val channel = target.Actor.toString
result.foreach { case (weapon, slots) => events ! BundledEnvelope(result.flatMap { case (weapon, slots) =>
slots.foreach { slot => slots.map { slot =>
events ! MessageEnvelope( MessageEnvelope(
channel, channel,
SendResponse(InventoryStateMessage(slot.Box.GUID, weapon.GUID, slot.Box.Capacity)) SendResponse(InventoryStateMessage(slot.Box.GUID, weapon.GUID, slot.Box.Capacity))
) )
} }
} })
!result.flatMap { _._2 }.exists { slot => slot.Magazine < slot.MaxMagazine() } !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.zones.Zone
import net.psforever.objects.{GlobalDefinitions, Player, SimpleItem} import net.psforever.objects.{GlobalDefinitions, Player, SimpleItem}
import net.psforever.packet.game.HackState1 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.base.message.SetEmpire
import net.psforever.services.vehicle.VehicleAction import net.psforever.services.vehicle.VehicleAction
import net.psforever.types.{PlanetSideEmpire, PlanetSideGUID} import net.psforever.types.{PlanetSideEmpire, PlanetSideGUID}
@ -145,14 +145,14 @@ class ImplantTerminalMechControl(mech: ImplantTerminalMech)
val zone = mech.Zone val zone = mech.Zone
val zoneId = zone.id val zoneId = zone.id
val events = zone.VehicleEvents val events = zone.VehicleEvents
mech.Seats.values.foreach(seat => events ! BundledEnvelope(mech.Seats.values.flatMap(seat =>
seat.occupant.collect { seat.occupant.collect {
case player => case player =>
seat.unmount(player) seat.unmount(player)
player.VehicleSeated = None 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 = { def powerTurnOnCallback(): Unit = {
@ -225,9 +225,9 @@ class ImplantTerminalMechControl(mech: ImplantTerminalMech)
setToFaction: PlanetSideEmpire.Value setToFaction: PlanetSideEmpire.Value
): Unit = { ): Unit = {
val events = zone.LocalEvents val events = zone.LocalEvents
opposingFactionsAre(setToFaction).foreach { faction => events ! BundledEnvelope(opposingFactionsAre(setToFaction).toSeq.map { faction =>
events ! MessageEnvelope(faction.toString, SetEmpire(guid, faction)) MessageEnvelope(faction.toString, SetEmpire(guid, faction))
} })
} }
private def noAccessByOpposingFactions( private def noAccessByOpposingFactions(
@ -236,9 +236,9 @@ class ImplantTerminalMechControl(mech: ImplantTerminalMech)
setToFaction: PlanetSideEmpire.Value setToFaction: PlanetSideEmpire.Value
): Unit = { ): Unit = {
val events = zone.LocalEvents val events = zone.LocalEvents
opposingFactionsAre(setToFaction).foreach { faction => events ! BundledEnvelope(opposingFactionsAre(setToFaction).toSeq.map { faction =>
events ! MessageEnvelope(faction.toString, SetEmpire(guid, setToFaction)) MessageEnvelope(faction.toString, SetEmpire(guid, setToFaction))
} })
} }
private def opposingFactionsAre(faction: PlanetSideEmpire.Value): PlanetSideEmpire.ValueSet = { private def opposingFactionsAre(faction: PlanetSideEmpire.Value): PlanetSideEmpire.ValueSet = {
@ -273,13 +273,13 @@ class ImplantTerminalMechControl(mech: ImplantTerminalMech)
): Unit = { ): Unit = {
val zoneId = zone.id val zoneId = zone.id
val events = zone.LocalEvents val events = zone.LocalEvents
obj.Seats.values.foreach(seat => events ! BundledEnvelope(obj.Seats.values.flatMap(seat =>
seat.occupant.collect { seat.occupant.collect {
case player if test(player.Faction) => case player if test(player.Faction) =>
seat.unmount(player) seat.unmount(player)
player.VehicleSeated = None 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.serverobject.turret.auto.{AffectedByAutomaticTurretFire, AutomatedTurret, AutomatedTurretBehavior}
import net.psforever.objects.vital.interaction.DamageResult import net.psforever.objects.vital.interaction.DamageResult
import net.psforever.packet.game.{ChangeFireModeMessage, HackState1} 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.base.message.SendResponse
import net.psforever.services.vehicle.support.TurretUpgrader import net.psforever.services.vehicle.support.TurretUpgrader
import net.psforever.services.vehicle.VehicleAction import net.psforever.services.vehicle.VehicleAction
@ -336,15 +336,15 @@ class FacilityTurretControl(turret: FacilityTurret)
val zone = turret.Zone val zone = turret.Zone
val zoneId = zone.id val zoneId = zone.id
val events = zone.VehicleEvents val events = zone.VehicleEvents
turret.Seats.values.zipWithIndex.foreach { events ! BundledEnvelope(turret.Seats.values.zipWithIndex.flatMap {
case (seat, seat_num) => case (seat, seat_num) =>
seat.occupant.collect { seat.occupant.collect {
case player => case player =>
seat.unmount(player) seat.unmount(player)
player.VehicleSeated = None 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) captureTerminalChanges(terminal, super.captureTerminalIsHacked, actionDelays = 3000L)
} }

View file

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

View file

@ -5,7 +5,7 @@ import net.psforever.objects.avatar.Certification
import net.psforever.objects.ce.Deployable import net.psforever.objects.ce.Deployable
import net.psforever.objects.{Player, Tool, TurretDeployable} import net.psforever.objects.{Player, Tool, TurretDeployable}
import net.psforever.packet.game.{HackMessage, HackState, HackState1, HackState7, InventoryStateMessage} 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.base.message.{SendResponse, SetEmpire}
import net.psforever.services.local.LocalAction import net.psforever.services.local.LocalAction
import net.psforever.services.vehicle.support.{TurretEnvelope, TurretUpgrader} import net.psforever.services.vehicle.support.{TurretEnvelope, TurretUpgrader}
@ -100,18 +100,18 @@ object WeaponTurrets {
val certs = hacker.avatar.certifications val certs = hacker.avatar.certifications
if (certs.contains(Certification.ExpertHacking) || certs.contains(Certification.ElectronicsExpert)) { if (certs.contains(Certification.ExpertHacking) || certs.contains(Certification.ElectronicsExpert)) {
// Forcefully dismount all seated occupants from the turret // Forcefully dismount all seated occupants from the turret
target.Seats.values.foreach { seat => zone.VehicleEvents ! BundledEnvelope(target.Seats.values.flatMap { seat =>
seat.occupant.collect { seat.occupant.collect {
player: Player => player: Player =>
seat.unmount(player) seat.unmount(player)
player.VehicleSeated = None player.VehicleSeated = None
zone.VehicleEvents ! MessageEnvelope( MessageEnvelope(
zone.id, zone.id,
player.GUID, player.GUID,
VehicleAction.KickPassenger(4, unk2 = false, target.GUID) VehicleAction.KickPassenger(4, unk2 = false, target.GUID)
) )
} }
} })
//hacker owns the deployable now //hacker owns the deployable now
target.OwnerGuid = None target.OwnerGuid = None
target.Actor ! Deployable.Ownership(hacker) 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.objects.Default
import net.psforever.types.{PlanetSideEmpire, Vector3} import net.psforever.types.{PlanetSideEmpire, Vector3}
import net.psforever.services.ServiceManager 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 net.psforever.services.galaxy.GalaxyAction
import scala.collection.mutable.ListBuffer import scala.collection.mutable.ListBuffer
@ -305,13 +305,15 @@ class ZoneHotSpotProjector(zone: Zone, hotspots: ListBuffer[HotSpotInfo], blanki
def UpdateHotSpots(affectedFactions: Iterable[PlanetSideEmpire.Value], hotSpotInfos: Iterable[HotSpotInfo]): Unit = { def UpdateHotSpots(affectedFactions: Iterable[PlanetSideEmpire.Value], hotSpotInfos: Iterable[HotSpotInfo]): Unit = {
val zoneNumber = zone.Number val zoneNumber = zone.Number
val hotSpotInfoList = hotSpotInfos.toList val hotSpotInfoList = hotSpotInfos.toList
affectedFactions.foreach(faction => galaxy ! BundledEnvelope(
galaxy ! MessageEnvelope(faction.toString, GalaxyAction.HotSpotUpdate( affectedFactions.map(faction =>
MessageEnvelope(faction.toString, GalaxyAction.HotSpotUpdate(
zoneNumber, zoneNumber,
1, 1,
ZoneHotSpotProjector.SpecificHotSpotInfo(faction, hotSpotInfoList) 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.serverobject.structures.{Building, WarpGate}
import net.psforever.objects.zones.Zone import net.psforever.objects.zones.Zone
import net.psforever.packet.game.ChatMsg 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.base.message.SendResponse
import net.psforever.services.galaxy.{GalaxyAction, GalaxyStamp} import net.psforever.services.galaxy.{GalaxyAction, GalaxyStamp}
import net.psforever.types.ChatMessageType import net.psforever.types.ChatMessageType
@ -576,16 +576,18 @@ class CavernRotationService(
def sendCavernRotationUpdatesToAll(galaxyService: ActorRef): Unit = { def sendCavernRotationUpdatesToAll(galaxyService: ActorRef): Unit = {
val curr = System.currentTimeMillis() val curr = System.currentTimeMillis()
val (lockedZones, unlockedZones) = managedZones.partition(_.locked) val (lockedZones, unlockedZones) = managedZones.partition(_.locked)
unlockedZones.foreach { z =>
galaxyService ! MessageEnvelope("", GalaxyAction.UnlockedZoneUpdate(z.zone))
}
val sortedLocked = lockedZones.sortBy(z => z.start) val sortedLocked = lockedZones.sortBy(z => z.start)
sortedLocked.take(2).foreach { z => galaxyService ! BundledEnvelope(
galaxyService ! MessageEnvelope("", GalaxyAction.LockedZoneUpdate(z.zone, z.start + z.duration - curr)) unlockedZones.map { z =>
} MessageEnvelope("", GalaxyAction.UnlockedZoneUpdate(z.zone))
sortedLocked.takeRight(2).foreach { z => } ++
galaxyService ! MessageEnvelope("", GalaxyAction.LockedZoneUpdate(z.zone, 0L)) 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.base.message.PlanetsideAttribute
import net.psforever.services.local.support.HackCaptureActor.GetHackingFaction import net.psforever.services.local.support.HackCaptureActor.GetHackingFaction
import net.psforever.services.local.LocalAction 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 java.util.concurrent.{Executors, TimeUnit}
import scala.collection.Seq import scala.collection.Seq
@ -247,7 +247,6 @@ class HackCaptureActor extends Actor {
// Notify all clients that CC has had its hack state changed // Notify all clients that CC has had its hack state changed
terminal.Zone.LocalEvents ! MessageEnvelope( terminal.Zone.LocalEvents ! MessageEnvelope(
terminal.Zone.id, terminal.Zone.id,
PlanetSideGUID(-1), /*what is this?, says the person who wrote it*/
PlanetsideAttribute( PlanetsideAttribute(
terminal.GUID, terminal.GUID,
PlanetsideAttributeEnum.ControlConsoleHackUpdate.id, 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.vehicles.MountedWeapons
import net.psforever.objects.zones.Zone import net.psforever.objects.zones.Zone
import net.psforever.services.base.{EventServiceSupport, GenericSupportEnvelopeOnly} 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.types.PlanetSideGUID
import net.psforever.services.base.support.{SimilarityComparator, SupportActor, SupportActorCaseConversions} import net.psforever.services.base.support.{SimilarityComparator, SupportActor, SupportActorCaseConversions}
import net.psforever.services.vehicle.VehicleAction import net.psforever.services.vehicle.VehicleAction
@ -245,15 +245,16 @@ class TurretUpgrader extends SupportActor[TurretUpgrader.Entry] {
trace(s"Wall turret finished ${target.Upgrade} upgrade") trace(s"Wall turret finished ${target.Upgrade} upgrade")
val targetGUID = target.GUID val targetGUID = target.GUID
if (target.Health > 0) { if (target.Health > 0) {
target.Weapons context.parent ! BundledEnvelope(target.Weapons
.map { case (index: Int, slot: EquipmentSlot) => (index, slot.Equipment) } .map { case (index: Int, slot: EquipmentSlot) => (index, slot.Equipment) }
.collect { .collect {
case (index, Some(tool: Tool)) => case (index, Some(tool: Tool)) =>
context.parent ! MessageEnvelope( MessageEnvelope(
zone.id, zone.id,
VehicleAction.EquipmentInSlot(targetGUID, index, tool) VehicleAction.EquipmentInSlot(targetGUID, index, tool)
) )
} }
)
} }
Finalize(target, entry.upgrade) Finalize(target, entry.upgrade)
} }