mirror of
https://github.com/2revoemag/PSF-BotServer.git
synced 2026-07-13 07:24:53 +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
662844b845
commit
c1d9f679b2
9 changed files with 235 additions and 7 deletions
|
|
@ -18,6 +18,7 @@ import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
|
||||||
import net.psforever.services.chat.{ChatChannel, DefaultChannel, SpectatorChannel}
|
import net.psforever.services.chat.{ChatChannel, DefaultChannel, SpectatorChannel}
|
||||||
import net.psforever.types.ChatMessageType.{CMT_TOGGLESPECTATORMODE, CMT_TOGGLE_GM}
|
import net.psforever.types.ChatMessageType.{CMT_TOGGLESPECTATORMODE, CMT_TOGGLE_GM}
|
||||||
import net.psforever.types.{ChatMessageType, PlanetSideEmpire}
|
import net.psforever.types.{ChatMessageType, PlanetSideEmpire}
|
||||||
|
import net.psforever.zones.Zones
|
||||||
|
|
||||||
import scala.util.Success
|
import scala.util.Success
|
||||||
|
|
||||||
|
|
@ -225,6 +226,7 @@ class ChatLogic(val ops: ChatOperations, implicit val context: ActorContext) ext
|
||||||
case "hidespectators" => customCommandHideSpectators()
|
case "hidespectators" => customCommandHideSpectators()
|
||||||
case "sayspectator" => customCommandSpeakAsSpectator(params, message)
|
case "sayspectator" => customCommandSpeakAsSpectator(params, message)
|
||||||
case "setempire" => customCommandSetEmpire(params)
|
case "setempire" => customCommandSetEmpire(params)
|
||||||
|
case "weaponlock" => customCommandZoneWeaponUnlock(session, params)
|
||||||
case _ =>
|
case _ =>
|
||||||
// command was not handled
|
// command was not handled
|
||||||
sendResponse(
|
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 = {
|
override def stop(): Unit = {
|
||||||
super.stop()
|
super.stop()
|
||||||
seeSpectatorsIn.foreach(_ => customCommandHideSpectators())
|
seeSpectatorsIn.foreach(_ => customCommandHideSpectators())
|
||||||
|
|
|
||||||
|
|
@ -8,9 +8,9 @@ import net.psforever.objects.serverobject.doors.Door
|
||||||
import net.psforever.objects.vehicles.MountableWeapons
|
import net.psforever.objects.vehicles.MountableWeapons
|
||||||
import net.psforever.objects.{BoomerDeployable, ExplosiveDeployable, TelepadDeployable, Tool, TurretDeployable}
|
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.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.services.local.LocalResponse
|
||||||
import net.psforever.types.{ChatMessageType, PlanetSideGUID}
|
import net.psforever.types.{ChatMessageType, PlanetSideGUID, SpawnGroup}
|
||||||
|
|
||||||
object LocalHandlerLogic {
|
object LocalHandlerLogic {
|
||||||
def apply(ops: SessionLocalHandlers): 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))
|
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 _ => ()
|
case _ => ()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -140,7 +140,7 @@ class ChatLogic(val ops: ChatOperations, implicit val context: ActorContext) ext
|
||||||
case _ => ("", Seq(""))
|
case _ => ("", Seq(""))
|
||||||
}
|
}
|
||||||
command match {
|
command match {
|
||||||
case "list" => ops.customCommandList(session, params, message)
|
case "list" => ops.customCommandList(session, params.toSeq, message)
|
||||||
case "nearby" => ops.customCommandNearby(session)
|
case "nearby" => ops.customCommandNearby(session)
|
||||||
case "loc" => ops.customCommandLoc(session, message)
|
case "loc" => ops.customCommandLoc(session, message)
|
||||||
case _ =>
|
case _ =>
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ import org.log4s.Logger
|
||||||
|
|
||||||
import java.util.concurrent.{Executors, TimeUnit}
|
import java.util.concurrent.{Executors, TimeUnit}
|
||||||
import scala.annotation.unused
|
import scala.annotation.unused
|
||||||
import scala.collection.{Seq, mutable}
|
import scala.collection.mutable
|
||||||
import scala.concurrent.duration._
|
import scala.concurrent.duration._
|
||||||
//
|
//
|
||||||
import net.psforever.actors.zone.BuildingActor
|
import net.psforever.actors.zone.BuildingActor
|
||||||
|
|
@ -1034,7 +1034,7 @@ class ChatOperations(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private def captureBaseParamFaction(
|
def captureBaseParamFaction(
|
||||||
@unused session: Session,
|
@unused session: Session,
|
||||||
token: Option[String]
|
token: Option[String]
|
||||||
): Option[PlanetSideEmpire.Value] = {
|
): Option[PlanetSideEmpire.Value] = {
|
||||||
|
|
@ -1307,6 +1307,28 @@ class ChatOperations(
|
||||||
str.replaceAll("\\s+", " ").trim.split("\\s").toList.filter(!_.equals(""))
|
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 = {
|
def commandIncomingSend(message: ChatMsg): Unit = {
|
||||||
sendResponse(message)
|
sendResponse(message)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2160,8 +2160,8 @@ class ZoningOperations(
|
||||||
tplayer.avatar = avatar
|
tplayer.avatar = avatar
|
||||||
session = session.copy(player = tplayer)
|
session = session.copy(player = tplayer)
|
||||||
//LoadMapMessage causes the client to send BeginZoningMessage, eventually leading to SetCurrentAvatar
|
//LoadMapMessage causes the client to send BeginZoningMessage, eventually leading to SetCurrentAvatar
|
||||||
val weaponsEnabled = !(mapName.equals("map11") || mapName.equals("map12") || mapName.equals("map13"))
|
//val weaponsEnabled = !(mapName.equals("map11") || mapName.equals("map12") || mapName.equals("map13"))
|
||||||
sendResponse(LoadMapMessage(mapName, id, 40100, 25, weaponsEnabled, map.checksum))
|
sendResponse(LoadMapMessage(mapName, id, 40100, 25, zone.LiveFireAllowed(tplayer.Faction), map.checksum))
|
||||||
if (isAcceptableNextSpawnPoint) {
|
if (isAcceptableNextSpawnPoint) {
|
||||||
//important! the LoadMapMessage must be processed by the client before the avatar is created
|
//important! the LoadMapMessage must be processed by the client before the avatar is created
|
||||||
player.allowInteraction = true
|
player.allowInteraction = true
|
||||||
|
|
|
||||||
|
|
@ -182,6 +182,12 @@ class Zone(val id: String, val map: ZoneMap, zoneNumber: Int) {
|
||||||
*/
|
*/
|
||||||
private var vehicleEvents: ActorRef = Default.Actor
|
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.
|
* When the zone has completed initializing, fulfill this promise.
|
||||||
* @see `init(ActorContext)`
|
* @see `init(ActorContext)`
|
||||||
|
|
@ -593,6 +599,46 @@ class Zone(val id: String, val map: ZoneMap, zoneNumber: Int) {
|
||||||
vehicleEvents = bus
|
vehicleEvents = bus
|
||||||
VehicleEvents
|
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)
|
LocalResponse.RechargeVehicleWeapon(vehicle_guid, weapon_guid)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
case LocalAction.ForceZoneChange(zone) =>
|
||||||
|
LocalEvents.publish(
|
||||||
|
LocalServiceResponse(
|
||||||
|
s"/$forChannel/Local",
|
||||||
|
Service.defaultPlayerGUID,
|
||||||
|
LocalResponse.ForceZoneChange(zone)
|
||||||
|
)
|
||||||
|
)
|
||||||
case _ => ;
|
case _ => ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -138,4 +138,5 @@ object LocalAction {
|
||||||
mountable_guid: PlanetSideGUID,
|
mountable_guid: PlanetSideGUID,
|
||||||
weapon_guid: PlanetSideGUID
|
weapon_guid: PlanetSideGUID
|
||||||
) extends Action
|
) 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.ce.{Deployable, DeployedItem}
|
||||||
import net.psforever.objects.serverobject.terminals.{ProximityUnit, Terminal}
|
import net.psforever.objects.serverobject.terminals.{ProximityUnit, Terminal}
|
||||||
import net.psforever.objects.vehicles.Utility
|
import net.psforever.objects.vehicles.Utility
|
||||||
|
import net.psforever.objects.zones.Zone
|
||||||
import net.psforever.packet.game.GenericObjectActionEnum.GenericObjectActionEnum
|
import net.psforever.packet.game.GenericObjectActionEnum.GenericObjectActionEnum
|
||||||
import net.psforever.packet.game.PlanetsideAttributeEnum.PlanetsideAttributeEnum
|
import net.psforever.packet.game.PlanetsideAttributeEnum.PlanetsideAttributeEnum
|
||||||
import net.psforever.packet.PlanetSideGamePacket
|
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 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 UpdateForceDomeStatus(building_guid: PlanetSideGUID, activated: Boolean) extends Response
|
||||||
final case class RechargeVehicleWeapon(mountable_guid: PlanetSideGUID, weapon_guid: PlanetSideGUID) extends Response
|
final case class RechargeVehicleWeapon(mountable_guid: PlanetSideGUID, weapon_guid: PlanetSideGUID) extends Response
|
||||||
|
final case class ForceZoneChange(zone: Zone) extends Response
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue