diff --git a/src/main/scala/net/psforever/actors/session/csr/ChatLogic.scala b/src/main/scala/net/psforever/actors/session/csr/ChatLogic.scala index 71b67bf80..13053039c 100644 --- a/src/main/scala/net/psforever/actors/session/csr/ChatLogic.scala +++ b/src/main/scala/net/psforever/actors/session/csr/ChatLogic.scala @@ -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 } diff --git a/src/main/scala/net/psforever/actors/session/csr/MountHandlerLogic.scala b/src/main/scala/net/psforever/actors/session/csr/MountHandlerLogic.scala index 32ef38de7..e7a3b4494 100644 --- a/src/main/scala/net/psforever/actors/session/csr/MountHandlerLogic.scala +++ b/src/main/scala/net/psforever/actors/session/csr/MountHandlerLogic.scala @@ -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 diff --git a/src/main/scala/net/psforever/actors/session/normal/AvatarHandlerLogic.scala b/src/main/scala/net/psforever/actors/session/normal/AvatarHandlerLogic.scala index 1a22a3bd2..43b21255f 100644 --- a/src/main/scala/net/psforever/actors/session/normal/AvatarHandlerLogic.scala +++ b/src/main/scala/net/psforever/actors/session/normal/AvatarHandlerLogic.scala @@ -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)) + ) } } diff --git a/src/main/scala/net/psforever/actors/session/normal/MountHandlerLogic.scala b/src/main/scala/net/psforever/actors/session/normal/MountHandlerLogic.scala index 4efc44ecd..aa0f86714 100644 --- a/src/main/scala/net/psforever/actors/session/normal/MountHandlerLogic.scala +++ b/src/main/scala/net/psforever/actors/session/normal/MountHandlerLogic.scala @@ -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 diff --git a/src/main/scala/net/psforever/actors/session/spectator/MountHandlerLogic.scala b/src/main/scala/net/psforever/actors/session/spectator/MountHandlerLogic.scala index 89ca48498..c56699848 100644 --- a/src/main/scala/net/psforever/actors/session/spectator/MountHandlerLogic.scala +++ b/src/main/scala/net/psforever/actors/session/spectator/MountHandlerLogic.scala @@ -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 diff --git a/src/main/scala/net/psforever/actors/session/support/GeneralOperations.scala b/src/main/scala/net/psforever/actors/session/support/GeneralOperations.scala index b11479e7f..3d34e5071 100644 --- a/src/main/scala/net/psforever/actors/session/support/GeneralOperations.scala +++ b/src/main/scala/net/psforever/actors/session/support/GeneralOperations.scala @@ -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 { diff --git a/src/main/scala/net/psforever/actors/session/support/SessionOutfitHandlers.scala b/src/main/scala/net/psforever/actors/session/support/SessionOutfitHandlers.scala index 25abda4c5..a47103dad 100644 --- a/src/main/scala/net/psforever/actors/session/support/SessionOutfitHandlers.scala +++ b/src/main/scala/net/psforever/actors/session/support/SessionOutfitHandlers.scala @@ -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)), diff --git a/src/main/scala/net/psforever/actors/session/support/ZoningOperations.scala b/src/main/scala/net/psforever/actors/session/support/ZoningOperations.scala index f99843679..3d2ab4e50 100644 --- a/src/main/scala/net/psforever/actors/session/support/ZoningOperations.scala +++ b/src/main/scala/net/psforever/actors/session/support/ZoningOperations.scala @@ -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 = { diff --git a/src/main/scala/net/psforever/objects/ce/DeployableBehavior.scala b/src/main/scala/net/psforever/objects/ce/DeployableBehavior.scala index 160776650..18a4585fa 100644 --- a/src/main/scala/net/psforever/objects/ce/DeployableBehavior.scala +++ b/src/main/scala/net/psforever/objects/ce/DeployableBehavior.scala @@ -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)) + }) } } } diff --git a/src/main/scala/net/psforever/objects/serverobject/damage/DamageableMountable.scala b/src/main/scala/net/psforever/objects/serverobject/damage/DamageableMountable.scala index ec076c715..90e859a9e 100644 --- a/src/main/scala/net/psforever/objects/serverobject/damage/DamageableMountable.scala +++ b/src/main/scala/net/psforever/objects/serverobject/damage/DamageableMountable.scala @@ -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) + } + ) } /** diff --git a/src/main/scala/net/psforever/objects/serverobject/damage/DamageableVehicle.scala b/src/main/scala/net/psforever/objects/serverobject/damage/DamageableVehicle.scala index 925484cab..4d609076a 100644 --- a/src/main/scala/net/psforever/objects/serverobject/damage/DamageableVehicle.scala +++ b/src/main/scala/net/psforever/objects/serverobject/damage/DamageableVehicle.scala @@ -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) ) diff --git a/src/main/scala/net/psforever/objects/serverobject/damage/DamageableWeaponTurret.scala b/src/main/scala/net/psforever/objects/serverobject/damage/DamageableWeaponTurret.scala index 7769ac6b8..250aa61c2 100644 --- a/src/main/scala/net/psforever/objects/serverobject/damage/DamageableWeaponTurret.scala +++ b/src/main/scala/net/psforever/objects/serverobject/damage/DamageableWeaponTurret.scala @@ -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) { diff --git a/src/main/scala/net/psforever/objects/serverobject/dome/ForceDomeControl.scala b/src/main/scala/net/psforever/objects/serverobject/dome/ForceDomeControl.scala index 2e67095b5..56a18b455 100644 --- a/src/main/scala/net/psforever/objects/serverobject/dome/ForceDomeControl.scala +++ b/src/main/scala/net/psforever/objects/serverobject/dome/ForceDomeControl.scala @@ -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) + }) } /** diff --git a/src/main/scala/net/psforever/objects/serverobject/repair/RepairableWeaponTurret.scala b/src/main/scala/net/psforever/objects/serverobject/repair/RepairableWeaponTurret.scala index 19579139c..5c716411f 100644 --- a/src/main/scala/net/psforever/objects/serverobject/repair/RepairableWeaponTurret.scala +++ b/src/main/scala/net/psforever/objects/serverobject/repair/RepairableWeaponTurret.scala @@ -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) ) } + ) } } diff --git a/src/main/scala/net/psforever/objects/serverobject/resourcesilo/ResourceSiloControl.scala b/src/main/scala/net/psforever/objects/serverobject/resourcesilo/ResourceSiloControl.scala index 8ba360041..9f6b2b0ff 100644 --- a/src/main/scala/net/psforever/objects/serverobject/resourcesilo/ResourceSiloControl.scala +++ b/src/main/scala/net/psforever/objects/serverobject/resourcesilo/ResourceSiloControl.scala @@ -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) } } diff --git a/src/main/scala/net/psforever/objects/serverobject/structures/participation/FacilityHackParticipation.scala b/src/main/scala/net/psforever/objects/serverobject/structures/participation/FacilityHackParticipation.scala index 27500e6ec..cb46bd630 100644 --- a/src/main/scala/net/psforever/objects/serverobject/structures/participation/FacilityHackParticipation.scala +++ b/src/main/scala/net/psforever/objects/serverobject/structures/participation/FacilityHackParticipation.scala @@ -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) + }) } } } diff --git a/src/main/scala/net/psforever/objects/serverobject/structures/participation/MajorFacilityHackParticipation.scala b/src/main/scala/net/psforever/objects/serverobject/structures/participation/MajorFacilityHackParticipation.scala index 47724f48c..a30211873 100644 --- a/src/main/scala/net/psforever/objects/serverobject/structures/participation/MajorFacilityHackParticipation.scala +++ b/src/main/scala/net/psforever/objects/serverobject/structures/participation/MajorFacilityHackParticipation.scala @@ -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) + }) } } diff --git a/src/main/scala/net/psforever/objects/serverobject/structures/participation/TowerHackParticipation.scala b/src/main/scala/net/psforever/objects/serverobject/structures/participation/TowerHackParticipation.scala index 7c65c07bd..08d2453da 100644 --- a/src/main/scala/net/psforever/objects/serverobject/structures/participation/TowerHackParticipation.scala +++ b/src/main/scala/net/psforever/objects/serverobject/structures/participation/TowerHackParticipation.scala @@ -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( diff --git a/src/main/scala/net/psforever/objects/serverobject/terminals/ProximityTerminalControl.scala b/src/main/scala/net/psforever/objects/serverobject/terminals/ProximityTerminalControl.scala index a68ca6548..c34eb6425 100644 --- a/src/main/scala/net/psforever/objects/serverobject/terminals/ProximityTerminalControl.scala +++ b/src/main/scala/net/psforever/objects/serverobject/terminals/ProximityTerminalControl.scala @@ -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() } } diff --git a/src/main/scala/net/psforever/objects/serverobject/terminals/implant/ImplantTerminalMechControl.scala b/src/main/scala/net/psforever/objects/serverobject/terminals/implant/ImplantTerminalMechControl.scala index fe4096b29..f35249851 100644 --- a/src/main/scala/net/psforever/objects/serverobject/terminals/implant/ImplantTerminalMechControl.scala +++ b/src/main/scala/net/psforever/objects/serverobject/terminals/implant/ImplantTerminalMechControl.scala @@ -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)) } - ) + )) } } diff --git a/src/main/scala/net/psforever/objects/serverobject/turret/FacilityTurretControl.scala b/src/main/scala/net/psforever/objects/serverobject/turret/FacilityTurretControl.scala index 54425f7e6..eaf927db0 100644 --- a/src/main/scala/net/psforever/objects/serverobject/turret/FacilityTurretControl.scala +++ b/src/main/scala/net/psforever/objects/serverobject/turret/FacilityTurretControl.scala @@ -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) } diff --git a/src/main/scala/net/psforever/objects/serverobject/turret/VanuSentryControl.scala b/src/main/scala/net/psforever/objects/serverobject/turret/VanuSentryControl.scala index 89c661277..38fbfb7ca 100644 --- a/src/main/scala/net/psforever/objects/serverobject/turret/VanuSentryControl.scala +++ b/src/main/scala/net/psforever/objects/serverobject/turret/VanuSentryControl.scala @@ -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() diff --git a/src/main/scala/net/psforever/objects/serverobject/turret/WeaponTurrets.scala b/src/main/scala/net/psforever/objects/serverobject/turret/WeaponTurrets.scala index a42ab78f2..742a8c67c 100644 --- a/src/main/scala/net/psforever/objects/serverobject/turret/WeaponTurrets.scala +++ b/src/main/scala/net/psforever/objects/serverobject/turret/WeaponTurrets.scala @@ -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) diff --git a/src/main/scala/net/psforever/objects/zones/ZoneHotSpotProjector.scala b/src/main/scala/net/psforever/objects/zones/ZoneHotSpotProjector.scala index 5d4efe87d..eb4b69958 100644 --- a/src/main/scala/net/psforever/objects/zones/ZoneHotSpotProjector.scala +++ b/src/main/scala/net/psforever/objects/zones/ZoneHotSpotProjector.scala @@ -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) )) + ) ) } } diff --git a/src/main/scala/net/psforever/services/CavernRotationService.scala b/src/main/scala/net/psforever/services/CavernRotationService.scala index 4b33229d1..ef3c83d3b 100644 --- a/src/main/scala/net/psforever/services/CavernRotationService.scala +++ b/src/main/scala/net/psforever/services/CavernRotationService.scala @@ -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)) + } + ) } /** diff --git a/src/main/scala/net/psforever/services/local/support/HackCaptureActor.scala b/src/main/scala/net/psforever/services/local/support/HackCaptureActor.scala index 61c27ec6f..dc579b915 100644 --- a/src/main/scala/net/psforever/services/local/support/HackCaptureActor.scala +++ b/src/main/scala/net/psforever/services/local/support/HackCaptureActor.scala @@ -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, diff --git a/src/main/scala/net/psforever/services/vehicle/support/TurretUpgrader.scala b/src/main/scala/net/psforever/services/vehicle/support/TurretUpgrader.scala index df81cb0ff..ae2ce9d51 100644 --- a/src/main/scala/net/psforever/services/vehicle/support/TurretUpgrader.scala +++ b/src/main/scala/net/psforever/services/vehicle/support/TurretUpgrader.scala @@ -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) }