mirror of
https://github.com/psforever/PSF-LoginServer.git
synced 2026-01-19 18:44:45 +00:00
No Safe Spaces (#1283)
* local zone maintains information about weapon fire capability per faction * map reload by faction to represent a change in weapons fire permissions via LMM
This commit is contained in:
parent
b8a47016da
commit
8e2732681c
|
|
@ -18,6 +18,7 @@ import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
|
|||
import net.psforever.services.chat.{ChatChannel, DefaultChannel, SpectatorChannel}
|
||||
import net.psforever.types.ChatMessageType.{CMT_TOGGLESPECTATORMODE, CMT_TOGGLE_GM}
|
||||
import net.psforever.types.{ChatMessageType, PlanetSideEmpire}
|
||||
import net.psforever.zones.Zones
|
||||
|
||||
import scala.util.Success
|
||||
|
||||
|
|
@ -225,6 +226,7 @@ class ChatLogic(val ops: ChatOperations, implicit val context: ActorContext) ext
|
|||
case "hidespectators" => customCommandHideSpectators()
|
||||
case "sayspectator" => customCommandSpeakAsSpectator(params, message)
|
||||
case "setempire" => customCommandSetEmpire(params)
|
||||
case "weaponlock" => customCommandZoneWeaponUnlock(session, params)
|
||||
case _ =>
|
||||
// command was not handled
|
||||
sendResponse(
|
||||
|
|
@ -411,6 +413,134 @@ class ChatLogic(val ops: ChatOperations, implicit val context: ActorContext) ext
|
|||
}
|
||||
}
|
||||
|
||||
def customCommandZoneWeaponUnlock(session: Session, params: Seq[String]): Boolean = {
|
||||
val usageMessage: Boolean = params.exists(_.matches("--help")) || params.exists(_.matches("-h"))
|
||||
val formattedParams = ops.cliCommaSeparatedParams(params)
|
||||
//handle params
|
||||
val (zoneList, verifiedZones, factionList, verifiedFactions, stateOpt) = (formattedParams.headOption, formattedParams.lift(1), formattedParams.lift(2)) match {
|
||||
case _ if usageMessage =>
|
||||
(Nil, Nil, Nil, Nil, None)
|
||||
|
||||
case (None, None, None) =>
|
||||
(
|
||||
Seq(session.zone.id),
|
||||
Seq(session.zone),
|
||||
PlanetSideEmpire.values.map(_.toString()).toSeq,
|
||||
PlanetSideEmpire.values.toSeq,
|
||||
Some(true)
|
||||
)
|
||||
|
||||
case (Some(zoneOrFaction), Some(factionOrZone), stateOpt) =>
|
||||
val factionOrZoneSplit = factionOrZone.split(",").toSeq
|
||||
val zoneOrFactionSplit = zoneOrFaction.split(",").toSeq
|
||||
val tryToFactions = factionOrZoneSplit.flatten(s => ops.captureBaseParamFaction(session, Some(s)))
|
||||
if (tryToFactions.isEmpty) {
|
||||
(
|
||||
factionOrZoneSplit,
|
||||
customCommandZoneParse(factionOrZoneSplit),
|
||||
zoneOrFactionSplit,
|
||||
zoneOrFactionSplit.flatten(s => ops.captureBaseParamFaction(session, Some(s))),
|
||||
customCommandOnOffStateOrNone(stateOpt)
|
||||
)
|
||||
} else {
|
||||
(
|
||||
zoneOrFactionSplit,
|
||||
customCommandZoneParse(zoneOrFactionSplit),
|
||||
factionOrZoneSplit,
|
||||
tryToFactions,
|
||||
customCommandOnOffStateOrNone(stateOpt)
|
||||
)
|
||||
}
|
||||
|
||||
case (Some(zoneOrFaction), stateOpt, None) =>
|
||||
val zoneOrFactionSplit = zoneOrFaction.split(",").toSeq
|
||||
val tryToFactions = zoneOrFactionSplit.flatten(s => ops.captureBaseParamFaction(session, Some(s)))
|
||||
if (tryToFactions.isEmpty) {
|
||||
(
|
||||
zoneOrFactionSplit,
|
||||
customCommandZoneParse(zoneOrFactionSplit),
|
||||
PlanetSideEmpire.values.map(_.toString()).toSeq,
|
||||
PlanetSideEmpire.values.toSeq,
|
||||
customCommandOnOffStateOrNone(stateOpt)
|
||||
)
|
||||
} else {
|
||||
(
|
||||
Seq(session.zone.id),
|
||||
Seq(session.zone),
|
||||
zoneOrFactionSplit,
|
||||
tryToFactions,
|
||||
customCommandOnOffStateOrNone(stateOpt)
|
||||
)
|
||||
}
|
||||
|
||||
case (stateOpt, None, None) =>
|
||||
(
|
||||
Seq(session.zone.id),
|
||||
Seq(session.zone),
|
||||
PlanetSideEmpire.values.map(_.toString()).toSeq,
|
||||
PlanetSideEmpire.values.toSeq,
|
||||
customCommandOnOffState(stateOpt)
|
||||
)
|
||||
}
|
||||
//resolve
|
||||
if (usageMessage) {
|
||||
sendResponse(ChatMsg(ChatMessageType.UNK_227, "!weaponlock [zone[,...]] [faction[,...]] [o[n]|of[f]]"))
|
||||
} else if (zoneList.isEmpty || verifiedZones.isEmpty || zoneList.size != verifiedZones.size) {
|
||||
sendResponse(ChatMsg(ChatMessageType.UNK_227, "some zones can not be verified"))
|
||||
} else if (factionList.isEmpty || verifiedFactions.isEmpty || factionList.size != verifiedFactions.size) {
|
||||
sendResponse(ChatMsg(ChatMessageType.UNK_227, "some factions can not be verified"))
|
||||
} else if (stateOpt.isEmpty) {
|
||||
sendResponse(ChatMsg(ChatMessageType.UNK_227, "state must be on or off"))
|
||||
} else {
|
||||
val state = !stateOpt.get
|
||||
verifiedZones.foreach { zone =>
|
||||
val events = zone.AvatarEvents
|
||||
val zoneId = zone.id
|
||||
//val reloadZoneMsg = AvatarAction.ReloadZone(zone)
|
||||
zone
|
||||
.UpdateLiveFireAllowed(state, verifiedFactions)
|
||||
.foreach {
|
||||
case (_, false, _) => ()
|
||||
case (faction, true, _) =>
|
||||
//events ! AvatarServiceMessage(s"$faction", reloadZoneMsg)
|
||||
}
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
private def customCommandOnOffStateOrNone(stateOpt: Option[String]): Option[Boolean] = {
|
||||
stateOpt match {
|
||||
case None =>
|
||||
Some(true)
|
||||
case _ =>
|
||||
customCommandOnOffState(stateOpt)
|
||||
}
|
||||
}
|
||||
|
||||
private def customCommandOnOffState(stateOpt: Option[String]): Option[Boolean] = {
|
||||
stateOpt match {
|
||||
case Some("o") | Some("on") =>
|
||||
Some(false)
|
||||
case Some("of") | Some("off") =>
|
||||
Some(true)
|
||||
case _ =>
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
def customCommandZoneParse(potentialZones: Seq[String]): Seq[Zone] = {
|
||||
potentialZones.flatten { potentialZone =>
|
||||
if (potentialZone.toIntOption.nonEmpty) {
|
||||
val xInt = potentialZone.toInt
|
||||
Zones.zones.find(_.Number == xInt)
|
||||
} else {
|
||||
Zones.zones.find(z => z.id.equals(potentialZone))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override def stop(): Unit = {
|
||||
super.stop()
|
||||
seeSpectatorsIn.foreach(_ => customCommandHideSpectators())
|
||||
|
|
|
|||
|
|
@ -8,9 +8,9 @@ import net.psforever.objects.serverobject.doors.Door
|
|||
import net.psforever.objects.vehicles.MountableWeapons
|
||||
import net.psforever.objects.{BoomerDeployable, ExplosiveDeployable, TelepadDeployable, Tool, TurretDeployable}
|
||||
import net.psforever.packet.game.{ChatMsg, DeployableObjectsInfoMessage, GenericActionMessage, GenericObjectActionMessage, GenericObjectStateMsg, HackMessage, HackState, HackState1, InventoryStateMessage, ObjectAttachMessage, ObjectCreateMessage, ObjectDeleteMessage, ObjectDetachMessage, OrbitalShuttleTimeMsg, PadAndShuttlePair, PlanetsideAttributeMessage, ProximityTerminalUseMessage, SetEmpireMessage, TriggerEffectMessage, TriggerSoundMessage, TriggeredSound, VehicleStateMessage}
|
||||
import net.psforever.services.Service
|
||||
import net.psforever.services.{InterstellarClusterService, Service}
|
||||
import net.psforever.services.local.LocalResponse
|
||||
import net.psforever.types.{ChatMessageType, PlanetSideGUID}
|
||||
import net.psforever.types.{ChatMessageType, PlanetSideGUID, SpawnGroup}
|
||||
|
||||
object LocalHandlerLogic {
|
||||
def apply(ops: SessionLocalHandlers): LocalHandlerLogic = {
|
||||
|
|
@ -240,6 +240,25 @@ class LocalHandlerLogic(val ops: SessionLocalHandlers, implicit val context: Act
|
|||
sendResponse(InventoryStateMessage(weapon.AmmoSlot.Box.GUID, weapon.GUID, weapon.Magazine))
|
||||
}
|
||||
|
||||
case LocalResponse.ForceZoneChange(zone) =>
|
||||
//todo we might be able to piggyback this for squad recalls later
|
||||
if(session.zone eq zone) {
|
||||
sessionLogic.zoning.zoneReload = true
|
||||
zone.AvatarEvents ! Service.Leave()
|
||||
zone.LocalEvents ! Service.Leave()
|
||||
zone.VehicleEvents ! Service.Leave()
|
||||
zone.AvatarEvents ! Service.Join(player.Name) //must manually restore this subscriptions
|
||||
sessionLogic.zoning.spawn.handleNewPlayerLoaded(player) //will restart subscriptions and dispatch a LoadMapMessage
|
||||
} else {
|
||||
import akka.actor.typed.scaladsl.adapter._
|
||||
sessionLogic.cluster ! InterstellarClusterService.GetRandomSpawnPoint(
|
||||
zone.Number,
|
||||
player.Faction,
|
||||
Seq(SpawnGroup.Facility, SpawnGroup.Tower, SpawnGroup.AMS),
|
||||
context.self
|
||||
)
|
||||
}
|
||||
|
||||
case _ => ()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -140,7 +140,7 @@ class ChatLogic(val ops: ChatOperations, implicit val context: ActorContext) ext
|
|||
case _ => ("", Seq(""))
|
||||
}
|
||||
command match {
|
||||
case "list" => ops.customCommandList(session, params, message)
|
||||
case "list" => ops.customCommandList(session, params.toSeq, message)
|
||||
case "nearby" => ops.customCommandNearby(session)
|
||||
case "loc" => ops.customCommandLoc(session, message)
|
||||
case _ =>
|
||||
|
|
|
|||
|
|
@ -1046,7 +1046,7 @@ class ChatOperations(
|
|||
}
|
||||
}
|
||||
|
||||
private def captureBaseParamFaction(
|
||||
def captureBaseParamFaction(
|
||||
@unused session: Session,
|
||||
token: Option[String]
|
||||
): Option[PlanetSideEmpire.Value] = {
|
||||
|
|
@ -1360,6 +1360,28 @@ class ChatOperations(
|
|||
str.replaceAll("\\s+", " ").trim.split("\\s").toList.filter(!_.equals(""))
|
||||
}
|
||||
|
||||
def cliCommaSeparatedParams(params: Seq[String]): Seq[String] = {
|
||||
var len = 0
|
||||
var appendNext = false
|
||||
var formattedParams: Seq[String] = Seq()
|
||||
params.foreach {
|
||||
case "," =>
|
||||
appendNext = true
|
||||
case param if appendNext || param.startsWith(",") =>
|
||||
formattedParams = formattedParams.slice(0, len - 1) :+ formattedParams(len - 1) + "," + param.replaceAll(",", "")
|
||||
appendNext = param.endsWith(",")
|
||||
case param if param.endsWith(",") =>
|
||||
formattedParams = formattedParams :+ param.take(param.length-1)
|
||||
len += 1
|
||||
appendNext = true
|
||||
case param =>
|
||||
formattedParams = formattedParams :+ param
|
||||
len += 1
|
||||
appendNext = false
|
||||
}
|
||||
formattedParams
|
||||
}
|
||||
|
||||
def commandIncomingSend(message: ChatMsg): Unit = {
|
||||
sendResponse(message)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2187,8 +2187,8 @@ class ZoningOperations(
|
|||
tplayer.avatar = avatar
|
||||
session = session.copy(player = tplayer)
|
||||
//LoadMapMessage causes the client to send BeginZoningMessage, eventually leading to SetCurrentAvatar
|
||||
val weaponsEnabled = !(mapName.equals("map11") || mapName.equals("map12") || mapName.equals("map13"))
|
||||
sendResponse(LoadMapMessage(mapName, id, 40100, 25, weaponsEnabled, map.checksum))
|
||||
//val weaponsEnabled = !(mapName.equals("map11") || mapName.equals("map12") || mapName.equals("map13"))
|
||||
sendResponse(LoadMapMessage(mapName, id, 40100, 25, zone.LiveFireAllowed(tplayer.Faction), map.checksum))
|
||||
if (isAcceptableNextSpawnPoint) {
|
||||
//important! the LoadMapMessage must be processed by the client before the avatar is created
|
||||
player.allowInteraction = true
|
||||
|
|
|
|||
|
|
@ -182,6 +182,12 @@ class Zone(val id: String, val map: ZoneMap, zoneNumber: Int) {
|
|||
*/
|
||||
private var vehicleEvents: ActorRef = Default.Actor
|
||||
|
||||
/**
|
||||
* Is any player permitted to engage in weapons discharge in this zone?
|
||||
*/
|
||||
private var liveFireAllowed: mutable.HashMap[PlanetSideEmpire.Value, Boolean] =
|
||||
mutable.HashMap.from(PlanetSideEmpire.values.map { f => (f, true) })
|
||||
|
||||
/**
|
||||
* When the zone has completed initializing, fulfill this promise.
|
||||
* @see `init(ActorContext)`
|
||||
|
|
@ -593,6 +599,46 @@ class Zone(val id: String, val map: ZoneMap, zoneNumber: Int) {
|
|||
vehicleEvents = bus
|
||||
VehicleEvents
|
||||
}
|
||||
|
||||
def LiveFireAllowed(): Boolean = liveFireAllowed.exists { case (_, v) => v }
|
||||
|
||||
def LiveFireAllowed(faction: PlanetSideEmpire.Value): Boolean = liveFireAllowed.getOrElse(faction, false)
|
||||
|
||||
def UpdateLiveFireAllowed(state: Boolean): List[(PlanetSideEmpire.Value, Boolean, Boolean)] = {
|
||||
val output = liveFireAllowed.map { case (f, v) =>
|
||||
(f, v == state, state)
|
||||
}
|
||||
output.foreach { case (f, _, v) =>
|
||||
liveFireAllowed.update(f, v)
|
||||
}
|
||||
output.toList
|
||||
}
|
||||
|
||||
def UpdateLiveFireAllowed(state: Boolean, faction: PlanetSideEmpire.Value): List[(PlanetSideEmpire.Value, Boolean, Boolean)] = {
|
||||
val output = liveFireAllowed.map { case (f, v) =>
|
||||
if (f == faction) {
|
||||
(f, v == state, state)
|
||||
} else {
|
||||
(f, false, v)
|
||||
}
|
||||
}
|
||||
liveFireAllowed.update(faction, state)
|
||||
output.toList
|
||||
}
|
||||
|
||||
def UpdateLiveFireAllowed(state: Boolean, factions: Seq[PlanetSideEmpire.Value]): List[(PlanetSideEmpire.Value, Boolean, Boolean)] = {
|
||||
val output = liveFireAllowed.map { case (f, v) =>
|
||||
if (factions.contains(f)) {
|
||||
(f, v == state, state)
|
||||
} else {
|
||||
(f, false, v)
|
||||
}
|
||||
}
|
||||
factions.foreach { f =>
|
||||
liveFireAllowed.update(f, state)
|
||||
}
|
||||
output.toList
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -306,6 +306,14 @@ class LocalService(zone: Zone) extends Actor {
|
|||
LocalResponse.RechargeVehicleWeapon(vehicle_guid, weapon_guid)
|
||||
)
|
||||
)
|
||||
case LocalAction.ForceZoneChange(zone) =>
|
||||
LocalEvents.publish(
|
||||
LocalServiceResponse(
|
||||
s"/$forChannel/Local",
|
||||
Service.defaultPlayerGUID,
|
||||
LocalResponse.ForceZoneChange(zone)
|
||||
)
|
||||
)
|
||||
case _ => ;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -138,4 +138,5 @@ object LocalAction {
|
|||
mountable_guid: PlanetSideGUID,
|
||||
weapon_guid: PlanetSideGUID
|
||||
) extends Action
|
||||
final case class ForceZoneChange(zone: Zone) extends Action
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import net.psforever.objects.{PlanetSideGameObject, TelepadDeployable, Vehicle}
|
|||
import net.psforever.objects.ce.{Deployable, DeployedItem}
|
||||
import net.psforever.objects.serverobject.terminals.{ProximityUnit, Terminal}
|
||||
import net.psforever.objects.vehicles.Utility
|
||||
import net.psforever.objects.zones.Zone
|
||||
import net.psforever.packet.game.GenericObjectActionEnum.GenericObjectActionEnum
|
||||
import net.psforever.packet.game.PlanetsideAttributeEnum.PlanetsideAttributeEnum
|
||||
import net.psforever.packet.PlanetSideGamePacket
|
||||
|
|
@ -86,4 +87,5 @@ object LocalResponse {
|
|||
final case class TriggerSound(sound: TriggeredSound.Value, pos: Vector3, unk: Int, volume: Float) extends Response
|
||||
final case class UpdateForceDomeStatus(building_guid: PlanetSideGUID, activated: Boolean) extends Response
|
||||
final case class RechargeVehicleWeapon(mountable_guid: PlanetSideGUID, weapon_guid: PlanetSideGUID) extends Response
|
||||
final case class ForceZoneChange(zone: Zone) extends Response
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue