mirror of
https://github.com/2revoemag/PSF-BotServer.git
synced 2026-01-20 02:24:45 +00:00
using force psm occlusion to eliminate certain other packets that would be fine if hidden
This commit is contained in:
parent
6f4ceaee29
commit
0628b988fe
|
|
@ -3,6 +3,7 @@ package net.psforever.actors.session.support
|
|||
|
||||
import akka.actor.typed.scaladsl.adapter._
|
||||
import akka.actor.{ActorContext, typed}
|
||||
import net.psforever.packet.game.objectcreate.ConstructorData
|
||||
import net.psforever.services.Service
|
||||
|
||||
import scala.collection.mutable
|
||||
|
|
@ -73,9 +74,9 @@ class SessionAvatarHandlers(
|
|||
canSeeReallyFar
|
||||
) if isNotSameTarget =>
|
||||
val pstateToSave = pstate.copy(timestamp = 0)
|
||||
val (lastMsg, lastTime, lastPosition, wasVisible) = lastSeenStreamMessage.get(guid.guid) match {
|
||||
case Some(SessionAvatarHandlers.LastUpstream(Some(msg), visible, time)) => (Some(msg), time, msg.pos, visible)
|
||||
case _ => (None, 0L, Vector3.Zero, false)
|
||||
val (lastMsg, lastTime, lastPosition, wasVisible, wasShooting) = lastSeenStreamMessage.get(guid.guid) match {
|
||||
case Some(SessionAvatarHandlers.LastUpstream(Some(msg), visible, shooting, time)) => (Some(msg), time, msg.pos, visible, shooting)
|
||||
case _ => (None, 0L, Vector3.Zero, false, None)
|
||||
}
|
||||
val drawConfig = Config.app.game.playerDraw //m
|
||||
val maxRange = drawConfig.rangeMax * drawConfig.rangeMax //sq.m
|
||||
|
|
@ -129,10 +130,10 @@ class SessionAvatarHandlers(
|
|||
isCloaking
|
||||
)
|
||||
)
|
||||
lastSeenStreamMessage.put(guid.guid, SessionAvatarHandlers.LastUpstream(Some(pstateToSave), visible=true, now))
|
||||
lastSeenStreamMessage.put(guid.guid, SessionAvatarHandlers.LastUpstream(Some(pstateToSave), visible=true, wasShooting, now))
|
||||
} else {
|
||||
//is visible, but skip reinforcement
|
||||
lastSeenStreamMessage.put(guid.guid, SessionAvatarHandlers.LastUpstream(Some(pstateToSave), visible=true, lastTime))
|
||||
lastSeenStreamMessage.put(guid.guid, SessionAvatarHandlers.LastUpstream(Some(pstateToSave), visible=true, wasShooting, lastTime))
|
||||
}
|
||||
} else {
|
||||
//conditions where the target is not currently visible
|
||||
|
|
@ -151,10 +152,10 @@ class SessionAvatarHandlers(
|
|||
is_cloaked = isCloaking
|
||||
)
|
||||
)
|
||||
lastSeenStreamMessage.put(guid.guid, SessionAvatarHandlers.LastUpstream(Some(pstateToSave), visible=false, now))
|
||||
lastSeenStreamMessage.put(guid.guid, SessionAvatarHandlers.LastUpstream(Some(pstateToSave), visible=false, wasShooting, now))
|
||||
} else {
|
||||
//skip drawing altogether
|
||||
lastSeenStreamMessage.put(guid.guid, SessionAvatarHandlers.LastUpstream(Some(pstateToSave), visible=false, lastTime))
|
||||
lastSeenStreamMessage.put(guid.guid, SessionAvatarHandlers.LastUpstream(Some(pstateToSave), visible=false, wasShooting, lastTime))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -179,10 +180,24 @@ class SessionAvatarHandlers(
|
|||
case AvatarResponse.ObjectHeld(_, previousSlot) =>
|
||||
sendResponse(ObjectHeldMessage(guid, previousSlot, unk1=false))
|
||||
|
||||
case AvatarResponse.ChangeFireState_Start(weaponGuid) if isNotSameTarget =>
|
||||
case AvatarResponse.ChangeFireState_Start(weaponGuid)
|
||||
if isNotSameTarget && lastSeenStreamMessage.get(guid.guid).exists { _.visible } =>
|
||||
sendResponse(ChangeFireStateMessage_Start(weaponGuid))
|
||||
val entry = lastSeenStreamMessage(guid.guid)
|
||||
lastSeenStreamMessage.put(guid.guid, entry.copy(shooting = Some(weaponGuid)))
|
||||
|
||||
case AvatarResponse.ChangeFireState_Start(weaponGuid)
|
||||
if isNotSameTarget =>
|
||||
sendResponse(ChangeFireStateMessage_Start(weaponGuid))
|
||||
|
||||
case AvatarResponse.ChangeFireState_Stop(weaponGuid) if isNotSameTarget =>
|
||||
case AvatarResponse.ChangeFireState_Stop(weaponGuid)
|
||||
if isNotSameTarget && lastSeenStreamMessage.get(guid.guid).exists { msg => msg.visible || msg.shooting.nonEmpty } =>
|
||||
sendResponse(ChangeFireStateMessage_Stop(weaponGuid))
|
||||
val entry = lastSeenStreamMessage(guid.guid)
|
||||
lastSeenStreamMessage.put(guid.guid, entry.copy(shooting = None))
|
||||
|
||||
case AvatarResponse.ChangeFireState_Stop(weaponGuid)
|
||||
if isNotSameTarget =>
|
||||
sendResponse(ChangeFireStateMessage_Stop(weaponGuid))
|
||||
|
||||
case AvatarResponse.LoadPlayer(pkt) if isNotSameTarget =>
|
||||
|
|
@ -388,7 +403,8 @@ class SessionAvatarHandlers(
|
|||
sendResponse(msg)
|
||||
|
||||
/* common messages (maybe once every respawn) */
|
||||
case AvatarResponse.Reload(itemGuid) if isNotSameTarget =>
|
||||
case AvatarResponse.Reload(itemGuid)
|
||||
if isNotSameTarget && lastSeenStreamMessage.get(guid.guid).exists { _.visible } =>
|
||||
sendResponse(ReloadMessage(itemGuid, ammo_clip=1, unk1=0))
|
||||
|
||||
case AvatarResponse.Killed(mount) =>
|
||||
|
|
@ -467,18 +483,14 @@ class SessionAvatarHandlers(
|
|||
)
|
||||
|
||||
/* uncommon messages (utility, or once in a while) */
|
||||
case AvatarResponse.ChangeAmmo(weapon_guid, weapon_slot, previous_guid, ammo_id, ammo_guid, ammo_data)
|
||||
if isNotSameTarget && lastSeenStreamMessage.get(guid.guid).exists { _.visible } =>
|
||||
changeAmmoProcedures(weapon_guid, previous_guid, ammo_id, ammo_guid, weapon_slot, ammo_data)
|
||||
sendResponse(ChangeAmmoMessage(weapon_guid, 1))
|
||||
|
||||
case AvatarResponse.ChangeAmmo(weapon_guid, weapon_slot, previous_guid, ammo_id, ammo_guid, ammo_data)
|
||||
if isNotSameTarget =>
|
||||
sendResponse(ObjectDetachMessage(weapon_guid, previous_guid, Vector3.Zero, 0))
|
||||
sendResponse(
|
||||
ObjectCreateMessage(
|
||||
ammo_id,
|
||||
ammo_guid,
|
||||
ObjectCreateMessageParent(weapon_guid, weapon_slot),
|
||||
ammo_data
|
||||
)
|
||||
)
|
||||
sendResponse(ChangeAmmoMessage(weapon_guid, 1))
|
||||
changeAmmoProcedures(weapon_guid, previous_guid, ammo_id, ammo_guid, weapon_slot, ammo_data)
|
||||
|
||||
case AvatarResponse.ChangeFireMode(itemGuid, mode) if isNotSameTarget =>
|
||||
sendResponse(ChangeFireModeMessage(itemGuid, mode))
|
||||
|
|
@ -546,21 +558,45 @@ class SessionAvatarHandlers(
|
|||
)
|
||||
)
|
||||
|
||||
case AvatarResponse.WeaponDryFire(weaponGuid) if isNotSameTarget =>
|
||||
case AvatarResponse.WeaponDryFire(weaponGuid)
|
||||
if isNotSameTarget && lastSeenStreamMessage.get(guid.guid).exists { _.visible } =>
|
||||
continent.GUID(weaponGuid).collect {
|
||||
case tool: Tool if tool.Magazine == 0 =>
|
||||
// check that the magazine is still empty before sending WeaponDryFireMessage
|
||||
// if it has been reloaded since then, other clients will not see it firing
|
||||
sendResponse(WeaponDryFireMessage(weaponGuid))
|
||||
case _ =>
|
||||
sendResponse(WeaponDryFireMessage(weaponGuid))
|
||||
}
|
||||
|
||||
case _ => ()
|
||||
}
|
||||
}
|
||||
|
||||
private def changeAmmoProcedures(
|
||||
weaponGuid: PlanetSideGUID,
|
||||
previousAmmoGuid: PlanetSideGUID,
|
||||
ammoTypeId: Int,
|
||||
ammoGuid: PlanetSideGUID,
|
||||
ammoSlot: Int,
|
||||
ammoData: ConstructorData
|
||||
): Unit = {
|
||||
sendResponse(ObjectDetachMessage(weaponGuid, previousAmmoGuid, Vector3.Zero, 0))
|
||||
//TODO? sendResponse(ObjectDeleteMessage(previousAmmoGuid, 0))
|
||||
sendResponse(
|
||||
ObjectCreateMessage(
|
||||
ammoTypeId,
|
||||
ammoGuid,
|
||||
ObjectCreateMessageParent(weaponGuid, ammoSlot),
|
||||
ammoData
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
object SessionAvatarHandlers {
|
||||
private[support] case class LastUpstream(msg: Option[AvatarResponse.PlayerState], visible: Boolean, time: Long)
|
||||
private[support] case class LastUpstream(
|
||||
msg: Option[AvatarResponse.PlayerState],
|
||||
visible: Boolean,
|
||||
shooting: Option[PlanetSideGUID],
|
||||
time: Long
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import net.psforever.objects.equipment.{Equipment, JammableMountedWeapons, Jamma
|
|||
import net.psforever.objects.guid.{GUIDTask, TaskWorkflow}
|
||||
import net.psforever.objects.serverobject.mount.Mountable
|
||||
import net.psforever.objects.serverobject.pad.VehicleSpawnPad
|
||||
import net.psforever.objects.{GlobalDefinitions, Player, Vehicle, Vehicles}
|
||||
import net.psforever.objects.{GlobalDefinitions, Player, Tool, Vehicle, Vehicles}
|
||||
import net.psforever.packet.game.objectcreate.ObjectCreateMessageParent
|
||||
import net.psforever.packet.game._
|
||||
import net.psforever.services.Service
|
||||
|
|
@ -79,6 +79,36 @@ class SessionVehicleHandlers(
|
|||
if isNotSameTarget =>
|
||||
sendResponse(FrameVehicleStateMessage(vguid, u1, pos, oient, vel, u2, u3, u4, is_crouched, u6, u7, u8, u9, uA))
|
||||
|
||||
case VehicleResponse.ChangeFireState_Start(weaponGuid) if isNotSameTarget =>
|
||||
sendResponse(ChangeFireStateMessage_Start(weaponGuid))
|
||||
|
||||
case VehicleResponse.ChangeFireState_Stop(weaponGuid) if isNotSameTarget =>
|
||||
sendResponse(ChangeFireStateMessage_Stop(weaponGuid))
|
||||
|
||||
case VehicleResponse.Reload(itemGuid) if isNotSameTarget =>
|
||||
sendResponse(ReloadMessage(itemGuid, ammo_clip=1, unk1=0))
|
||||
|
||||
case VehicleResponse.ChangeAmmo(weapon_guid, weapon_slot, previous_guid, ammo_id, ammo_guid, ammo_data) if isNotSameTarget =>
|
||||
sendResponse(ObjectDetachMessage(weapon_guid, previous_guid, Vector3.Zero, 0))
|
||||
//TODO? sendResponse(ObjectDeleteMessage(previousAmmoGuid, 0))
|
||||
sendResponse(
|
||||
ObjectCreateMessage(
|
||||
ammo_id,
|
||||
ammo_guid,
|
||||
ObjectCreateMessageParent(weapon_guid, weapon_slot),
|
||||
ammo_data
|
||||
)
|
||||
)
|
||||
sendResponse(ChangeAmmoMessage(weapon_guid, 1))
|
||||
|
||||
case VehicleResponse.WeaponDryFire(weaponGuid) if isNotSameTarget =>
|
||||
continent.GUID(weaponGuid).collect {
|
||||
case tool: Tool if tool.Magazine == 0 =>
|
||||
// check that the magazine is still empty before sending WeaponDryFireMessage
|
||||
// if it has been reloaded since then, other clients will not see it firing
|
||||
sendResponse(WeaponDryFireMessage(weaponGuid))
|
||||
}
|
||||
|
||||
case VehicleResponse.DismountVehicle(bailType, wasKickedByDriver) if isNotSameTarget =>
|
||||
sendResponse(DismountVehicleMsg(guid, bailType, wasKickedByDriver))
|
||||
|
||||
|
|
@ -330,10 +360,10 @@ class SessionVehicleHandlers(
|
|||
}
|
||||
|
||||
private def changeLoadoutDeleteOldEquipment(
|
||||
vehicle: Vehicle,
|
||||
oldWeapons: Iterable[(Equipment, PlanetSideGUID)],
|
||||
oldInventory: Iterable[(Equipment, PlanetSideGUID)]
|
||||
): Unit = {
|
||||
vehicle: Vehicle,
|
||||
oldWeapons: Iterable[(Equipment, PlanetSideGUID)],
|
||||
oldInventory: Iterable[(Equipment, PlanetSideGUID)]
|
||||
): Unit = {
|
||||
vehicle.PassengerInSeat(player) match {
|
||||
case Some(seatNum) =>
|
||||
//participant: observe changes to equipment
|
||||
|
|
|
|||
|
|
@ -271,10 +271,6 @@ class VehicleOperations(
|
|||
sessionData.validObject(mountable_guid, decorator = "MountVehicle").collect {
|
||||
case obj: Mountable =>
|
||||
obj.Actor ! Mountable.TryMount(player, entry_point)
|
||||
case _: Mountable =>
|
||||
log.warn(
|
||||
s"DismountVehicleMsg: ${player.Name} can not mount while server has asserted control; please wait"
|
||||
)
|
||||
case _ =>
|
||||
log.error(s"MountVehicleMsg: object ${mountable_guid.guid} not a mountable thing, ${player.Name}")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -74,19 +74,28 @@ private[support] class WeaponAndProjectileOperations(
|
|||
|
||||
def handleWeaponDryFire(pkt: WeaponDryFireMessage): Unit = {
|
||||
val WeaponDryFireMessage(weapon_guid) = pkt
|
||||
FindWeapon
|
||||
val (containerOpt, tools) = FindContainedWeapon
|
||||
tools
|
||||
.find { _.GUID == weapon_guid }
|
||||
.orElse { continent.GUID(weapon_guid) } match {
|
||||
case Some(_: Equipment) =>
|
||||
continent.AvatarEvents ! AvatarServiceMessage(
|
||||
continent.id,
|
||||
AvatarAction.WeaponDryFire(player.GUID, weapon_guid)
|
||||
)
|
||||
case _ =>
|
||||
.orElse { continent.GUID(weapon_guid) }
|
||||
.collect {
|
||||
case _: Equipment if containerOpt.exists(_.isInstanceOf[Player]) =>
|
||||
continent.AvatarEvents ! AvatarServiceMessage(
|
||||
continent.id,
|
||||
AvatarAction.WeaponDryFire(player.GUID, weapon_guid)
|
||||
)
|
||||
case _: Equipment =>
|
||||
continent.VehicleEvents ! VehicleServiceMessage(
|
||||
continent.id,
|
||||
VehicleAction.WeaponDryFire(player.GUID, weapon_guid)
|
||||
)
|
||||
}
|
||||
.orElse {
|
||||
log.warn(
|
||||
s"WeaponDryFire: ${player.Name}'s weapon ${weapon_guid.guid} is either not a weapon or does not exist"
|
||||
)
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
def handleWeaponLazeTargetPosition(pkt: WeaponLazeTargetPositionMessage): Unit = {
|
||||
|
|
@ -111,45 +120,16 @@ private[support] class WeaponAndProjectileOperations(
|
|||
val ChangeFireStateMessage_Start(item_guid) = pkt
|
||||
if (shooting.isEmpty) {
|
||||
sessionData.findEquipment(item_guid) match {
|
||||
case Some(tool: Tool) if player.VehicleSeated.isEmpty =>
|
||||
fireStateStartWhenPlayer(tool, item_guid)
|
||||
case Some(tool: Tool) =>
|
||||
if (tool.FireMode.RoundsPerShot == 0 || tool.Magazine > 0 || prefire.contains(item_guid)) {
|
||||
prefire -= item_guid
|
||||
shooting += item_guid
|
||||
shootingStart += item_guid -> System.currentTimeMillis()
|
||||
ongoingShotsFired = 0
|
||||
//special case - suppress the decimator's alternate fire mode, by projectile
|
||||
if (tool.Projectile != GlobalDefinitions.phoenix_missile_guided_projectile) {
|
||||
continent.AvatarEvents ! AvatarServiceMessage(
|
||||
continent.id,
|
||||
AvatarAction.ChangeFireState_Start(player.GUID, item_guid)
|
||||
)
|
||||
}
|
||||
//charge ammunition drain
|
||||
tool.FireMode match {
|
||||
case mode: ChargeFireModeDefinition =>
|
||||
sessionData.progressBarValue = Some(0f)
|
||||
sessionData.progressBarUpdate = context.system.scheduler.scheduleOnce(
|
||||
(mode.Time + mode.DrainInterval) milliseconds,
|
||||
context.self,
|
||||
SessionActor.ProgressEvent(1f, () => {}, Tools.ChargeFireMode(player, tool), mode.DrainInterval)
|
||||
)
|
||||
case _ => ;
|
||||
}
|
||||
} else {
|
||||
log.warn(
|
||||
s"ChangeFireState_Start: ${player.Name}'s ${tool.Definition.Name} magazine was empty before trying to shoot"
|
||||
)
|
||||
EmptyMagazine(item_guid, tool)
|
||||
}
|
||||
case Some(_) => //permissible, for now
|
||||
prefire -= item_guid
|
||||
shooting += item_guid
|
||||
shootingStart += item_guid -> System.currentTimeMillis()
|
||||
ongoingShotsFired = 0
|
||||
continent.AvatarEvents ! AvatarServiceMessage(
|
||||
continent.id,
|
||||
AvatarAction.ChangeFireState_Start(player.GUID, item_guid)
|
||||
)
|
||||
fireStateStartWhenMounted(tool, item_guid)
|
||||
case Some(_) if player.VehicleSeated.isEmpty =>
|
||||
fireStateStartSetup(item_guid)
|
||||
fireStateStartPlayerMessages(item_guid)
|
||||
case Some(_) =>
|
||||
fireStateStartSetup(item_guid)
|
||||
fireStateStartMountedMessages(item_guid)
|
||||
case None =>
|
||||
log.warn(s"ChangeFireState_Start: can not find $item_guid")
|
||||
}
|
||||
|
|
@ -162,48 +142,23 @@ private[support] class WeaponAndProjectileOperations(
|
|||
prefire -= item_guid
|
||||
shootingStop += item_guid -> now
|
||||
shooting -= item_guid
|
||||
val pguid = player.GUID
|
||||
sessionData.findEquipment(item_guid) match {
|
||||
case Some(tool: Tool) if player.VehicleSeated.isEmpty =>
|
||||
fireStateStopWhenPlayer(tool, item_guid)
|
||||
case Some(tool: Tool) =>
|
||||
//the decimator does not send a ChangeFireState_Start on the last shot; heaven knows why
|
||||
if (
|
||||
tool.Definition == GlobalDefinitions.phoenix &&
|
||||
tool.Projectile != GlobalDefinitions.phoenix_missile_guided_projectile
|
||||
) {
|
||||
//suppress the decimator's alternate fire mode, however
|
||||
continent.AvatarEvents ! AvatarServiceMessage(
|
||||
continent.id,
|
||||
AvatarAction.ChangeFireState_Start(pguid, item_guid)
|
||||
)
|
||||
shootingStart += item_guid -> (now - 1L)
|
||||
}
|
||||
avatarActor ! AvatarActor.UpdateToolDischarge(EquipmentStat(tool.Definition.ObjectId,ongoingShotsFired,0,0))
|
||||
tool.FireMode match {
|
||||
case _: ChargeFireModeDefinition =>
|
||||
sendResponse(QuantityUpdateMessage(tool.AmmoSlot.Box.GUID, tool.Magazine))
|
||||
case _ => ;
|
||||
}
|
||||
if (tool.Magazine == 0) {
|
||||
FireCycleCleanup(tool)
|
||||
}
|
||||
continent.AvatarEvents ! AvatarServiceMessage(
|
||||
continent.id,
|
||||
AvatarAction.ChangeFireState_Stop(pguid, item_guid)
|
||||
)
|
||||
|
||||
fireStateStopWhenMounted(tool, item_guid)
|
||||
case Some(trigger: BoomerTrigger) =>
|
||||
continent.AvatarEvents ! AvatarServiceMessage(
|
||||
continent.id,
|
||||
AvatarAction.ChangeFireState_Start(pguid, item_guid)
|
||||
)
|
||||
continent.GUID(trigger.Companion) match {
|
||||
case Some(boomer: BoomerDeployable) =>
|
||||
fireStateStopPlayerMessages(item_guid)
|
||||
continent.GUID(trigger.Companion).collect {
|
||||
case boomer: BoomerDeployable =>
|
||||
boomer.Actor ! CommonMessages.Use(player, Some(trigger))
|
||||
case Some(_) | None => ;
|
||||
}
|
||||
|
||||
case _ => ;
|
||||
//log.warn(s"ChangeFireState_Stop: ${player.Name} never started firing item ${item_guid.guid} in the first place?")
|
||||
case Some(_) if player.VehicleSeated.isEmpty =>
|
||||
fireStateStopPlayerMessages(item_guid)
|
||||
case Some(_) =>
|
||||
fireStateStopMountedMessages(item_guid)
|
||||
case _ => ()
|
||||
log.warn(s"ChangeFireState_Stop: can not find $item_guid")
|
||||
}
|
||||
sessionData.progressBarUpdate.cancel()
|
||||
sessionData.progressBarValue = None
|
||||
|
|
@ -212,54 +167,10 @@ private[support] class WeaponAndProjectileOperations(
|
|||
def handleReload(pkt: ReloadMessage): Unit = {
|
||||
val ReloadMessage(item_guid, _, unk1) = pkt
|
||||
FindContainedWeapon match {
|
||||
case (Some(obj: Player), tools) =>
|
||||
handleReloadWhenPlayer(item_guid, obj, tools, unk1)
|
||||
case (Some(obj: PlanetSideServerObject with Container), tools) =>
|
||||
tools.filter { _.GUID == item_guid }.foreach { tool =>
|
||||
val currentMagazine : Int = tool.Magazine
|
||||
val magazineSize : Int = tool.MaxMagazine
|
||||
val reloadValue : Int = magazineSize - currentMagazine
|
||||
if (magazineSize > 0 && reloadValue > 0) {
|
||||
FindEquipmentStock(obj, FindAmmoBoxThatUses(tool.AmmoType), reloadValue, CountAmmunition).reverse match {
|
||||
case Nil => ;
|
||||
case x :: xs =>
|
||||
val (deleteFunc, modifyFunc) : (Equipment => Future[Any], (AmmoBox, Int) => Unit) = obj match {
|
||||
case veh : Vehicle =>
|
||||
(RemoveOldEquipmentFromInventory(veh)(_), ModifyAmmunitionInVehicle(veh)(_, _))
|
||||
case _ =>
|
||||
(RemoveOldEquipmentFromInventory(obj)(_), ModifyAmmunition(obj)(_, _))
|
||||
}
|
||||
xs.foreach { item => deleteFunc(item.obj) }
|
||||
val box = x.obj.asInstanceOf[AmmoBox]
|
||||
val tailReloadValue : Int = if (xs.isEmpty) {
|
||||
0
|
||||
}
|
||||
else {
|
||||
xs.map(_.obj.asInstanceOf[AmmoBox].Capacity).sum
|
||||
}
|
||||
val sumReloadValue : Int = box.Capacity + tailReloadValue
|
||||
val actualReloadValue = if (sumReloadValue <= reloadValue) {
|
||||
deleteFunc(box)
|
||||
sumReloadValue
|
||||
}
|
||||
else {
|
||||
modifyFunc(box, reloadValue - tailReloadValue)
|
||||
reloadValue
|
||||
}
|
||||
val finalReloadValue = actualReloadValue + currentMagazine
|
||||
log.info(
|
||||
s"${player.Name} successfully reloaded $reloadValue ${tool.AmmoType} into ${tool.Definition.Name}"
|
||||
)
|
||||
tool.Magazine = finalReloadValue
|
||||
sendResponse(ReloadMessage(item_guid, finalReloadValue, unk1))
|
||||
continent.AvatarEvents ! AvatarServiceMessage(
|
||||
continent.id,
|
||||
AvatarAction.Reload(player.GUID, item_guid)
|
||||
)
|
||||
}
|
||||
} else {
|
||||
//the weapon can not reload due to full magazine; the UI for the magazine is obvious bugged, so fix it
|
||||
sendResponse(QuantityUpdateMessage(tool.AmmoSlot.Box.GUID, magazineSize))
|
||||
}
|
||||
}
|
||||
handleReloadWhenMountable(item_guid, obj, tools, unk1)
|
||||
case (_, _) =>
|
||||
log.warn(s"ReloadMessage: either can not find $item_guid or the object found was not a Tool")
|
||||
}
|
||||
|
|
@ -272,17 +183,19 @@ private[support] class WeaponAndProjectileOperations(
|
|||
log.warn(s"ChangeAmmo: either can not find $item_guid or the object found was not Equipment")
|
||||
} else {
|
||||
equipment foreach {
|
||||
case obj : ConstructionItem =>
|
||||
case obj: ConstructionItem =>
|
||||
if (Deployables.performConstructionItemAmmoChange(player.avatar.certifications, obj, obj.AmmoTypeIndex)) {
|
||||
log.info(
|
||||
s"${player.Name} switched ${player.Sex.possessive} ${obj.Definition.Name} to construct ${obj.AmmoType} (option #${obj.FireModeIndex})"
|
||||
)
|
||||
sendResponse(ChangeAmmoMessage(obj.GUID, obj.AmmoTypeIndex))
|
||||
}
|
||||
case tool : Tool =>
|
||||
case tool: Tool =>
|
||||
thing match {
|
||||
case Some(correctThing: PlanetSideServerObject with Container) =>
|
||||
PerformToolAmmoChange(tool, correctThing)
|
||||
case Some(player: Player) =>
|
||||
PerformToolAmmoChange(tool, player, ModifyAmmunition(player))
|
||||
case Some(mountable: PlanetSideServerObject with Container) =>
|
||||
PerformToolAmmoChange(tool, mountable, ModifyAmmunitionInMountable(mountable))
|
||||
case _ =>
|
||||
log.warn(s"ChangeAmmo: the ${thing.get.Definition.Name} in ${player.Name}'s is not the correct type")
|
||||
}
|
||||
|
|
@ -804,7 +717,7 @@ private[support] class WeaponAndProjectileOperations(
|
|||
* @param reloadValue the value to modify the `AmmoBox`;
|
||||
* subtracted from the current `Capacity` of `Box`
|
||||
*/
|
||||
def ModifyAmmunitionInVehicle(obj: Vehicle)(box: AmmoBox, reloadValue: Int): Unit = {
|
||||
def ModifyAmmunitionInMountable(obj: PlanetSideServerObject with Container)(box: AmmoBox, reloadValue: Int): Unit = {
|
||||
ModifyAmmunition(obj)(box, reloadValue)
|
||||
obj.Find(box) match {
|
||||
case Some(index) =>
|
||||
|
|
@ -827,19 +740,19 @@ private[support] class WeaponAndProjectileOperations(
|
|||
* @param tool na
|
||||
* @param obj na
|
||||
*/
|
||||
def PerformToolAmmoChange(tool: Tool, obj: PlanetSideServerObject with Container): Unit = {
|
||||
def PerformToolAmmoChange(
|
||||
tool: Tool,
|
||||
obj: PlanetSideServerObject with Container,
|
||||
modifyFunc: (AmmoBox, Int) => Unit
|
||||
): Unit = {
|
||||
val originalAmmoType = tool.AmmoType
|
||||
do {
|
||||
val requestedAmmoType = tool.NextAmmoType
|
||||
val fullMagazine = tool.MaxMagazine
|
||||
if (requestedAmmoType != tool.AmmoSlot.Box.AmmoType) {
|
||||
FindEquipmentStock(obj, FindAmmoBoxThatUses(requestedAmmoType), fullMagazine, CountAmmunition).reverse match {
|
||||
case Nil => ;
|
||||
case Nil => ()
|
||||
case x :: xs =>
|
||||
val modifyFunc: (AmmoBox, Int) => Unit = obj match {
|
||||
case veh: Vehicle => ModifyAmmunitionInVehicle(veh)
|
||||
case _ => ModifyAmmunition(obj)
|
||||
}
|
||||
val stowNewFunc: Equipment => TaskBundle = PutNewEquipmentInInventoryOrDrop(obj)
|
||||
val stowFunc: Equipment => Future[Any] = PutEquipmentInInventoryOrDrop(obj)
|
||||
|
||||
|
|
@ -1231,13 +1144,233 @@ private[support] class WeaponAndProjectileOperations(
|
|||
*/
|
||||
def FindWeapon: Set[Tool] = FindContainedWeapon._2
|
||||
|
||||
/*
|
||||
used by ChangeFireStateMessage_Start handling
|
||||
*/
|
||||
private def fireStateStartSetup(itemGuid: PlanetSideGUID): Unit = {
|
||||
prefire -= itemGuid
|
||||
shooting += itemGuid
|
||||
shootingStart += itemGuid -> System.currentTimeMillis()
|
||||
ongoingShotsFired = 0
|
||||
}
|
||||
|
||||
private def fireStateStartChargeMode(tool: Tool): Unit = {
|
||||
//charge ammunition drain
|
||||
tool.FireMode match {
|
||||
case mode: ChargeFireModeDefinition =>
|
||||
sessionData.progressBarValue = Some(0f)
|
||||
sessionData.progressBarUpdate = context.system.scheduler.scheduleOnce(
|
||||
(mode.Time + mode.DrainInterval) milliseconds,
|
||||
context.self,
|
||||
SessionActor.ProgressEvent(1f, () => {}, Tools.ChargeFireMode(player, tool), mode.DrainInterval)
|
||||
)
|
||||
case _ => ()
|
||||
}
|
||||
}
|
||||
|
||||
private def fireStateStartPlayerMessages(itemGuid: PlanetSideGUID): Unit = {
|
||||
continent.AvatarEvents ! AvatarServiceMessage(
|
||||
continent.id,
|
||||
AvatarAction.ChangeFireState_Start(player.GUID, itemGuid)
|
||||
)
|
||||
}
|
||||
|
||||
private def fireStateStartMountedMessages(itemGuid: PlanetSideGUID): Unit = {
|
||||
continent.VehicleEvents ! VehicleServiceMessage(
|
||||
continent.id,
|
||||
VehicleAction.ChangeFireState_Start(player.GUID, itemGuid)
|
||||
)
|
||||
}
|
||||
|
||||
private def allowFireStateChangeStart(tool: Tool, itemGuid: PlanetSideGUID): Boolean = {
|
||||
tool.FireMode.RoundsPerShot == 0 || tool.Magazine > 0 || prefire.contains(itemGuid)
|
||||
}
|
||||
|
||||
private def enforceEmptyMagazine(tool: Tool, itemGuid: PlanetSideGUID): Unit = {
|
||||
log.warn(
|
||||
s"ChangeFireState_Start: ${player.Name}'s ${tool.Definition.Name} magazine was empty before trying to shoot"
|
||||
)
|
||||
EmptyMagazine(itemGuid, tool)
|
||||
}
|
||||
|
||||
private def fireStateStartWhenPlayer(tool: Tool, itemGuid: PlanetSideGUID): Unit = {
|
||||
if (allowFireStateChangeStart(tool, itemGuid)) {
|
||||
fireStateStartSetup(itemGuid)
|
||||
//special case - suppress the decimator's alternate fire mode, by projectile
|
||||
if (tool.Projectile != GlobalDefinitions.phoenix_missile_guided_projectile) {
|
||||
fireStateStartPlayerMessages(itemGuid)
|
||||
}
|
||||
fireStateStartChargeMode(tool)
|
||||
} else {
|
||||
enforceEmptyMagazine(tool, itemGuid)
|
||||
}
|
||||
}
|
||||
|
||||
private def fireStateStartWhenMounted(tool: Tool, itemGuid: PlanetSideGUID): Unit = {
|
||||
if (allowFireStateChangeStart(tool, itemGuid)) {
|
||||
fireStateStartSetup(itemGuid)
|
||||
fireStateStartMountedMessages(itemGuid)
|
||||
fireStateStartChargeMode(tool)
|
||||
} else {
|
||||
enforceEmptyMagazine(tool, itemGuid)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
used by ChangeFireStateMessage_Stop handling
|
||||
*/
|
||||
private def fireStateStopUpdateChargeAndCleanup(tool: Tool): Unit = {
|
||||
avatarActor ! AvatarActor.UpdateToolDischarge(EquipmentStat(tool.Definition.ObjectId, ongoingShotsFired, 0, 0))
|
||||
tool.FireMode match {
|
||||
case _: ChargeFireModeDefinition =>
|
||||
sendResponse(QuantityUpdateMessage(tool.AmmoSlot.Box.GUID, tool.Magazine))
|
||||
case _ => ;
|
||||
}
|
||||
if (tool.Magazine == 0) {
|
||||
FireCycleCleanup(tool)
|
||||
}
|
||||
}
|
||||
|
||||
private def fireStateStopPlayerMessages(itemGuid: PlanetSideGUID): Unit = {
|
||||
continent.AvatarEvents ! AvatarServiceMessage(
|
||||
continent.id,
|
||||
AvatarAction.ChangeFireState_Stop(player.GUID, itemGuid)
|
||||
)
|
||||
}
|
||||
|
||||
private def fireStateStopMountedMessages(itemGuid: PlanetSideGUID): Unit = {
|
||||
continent.VehicleEvents ! VehicleServiceMessage(
|
||||
continent.id,
|
||||
VehicleAction.ChangeFireState_Stop(player.GUID, itemGuid)
|
||||
)
|
||||
}
|
||||
|
||||
private def fireStateStopWhenPlayer(tool: Tool, itemGuid: PlanetSideGUID): Unit = {
|
||||
//the decimator does not send a ChangeFireState_Start on the last shot; heaven knows why
|
||||
//suppress the decimator's alternate fire mode, however
|
||||
if (
|
||||
tool.Definition == GlobalDefinitions.phoenix &&
|
||||
tool.Projectile != GlobalDefinitions.phoenix_missile_guided_projectile
|
||||
) {
|
||||
fireStateStartPlayerMessages(itemGuid)
|
||||
}
|
||||
fireStateStopUpdateChargeAndCleanup(tool)
|
||||
fireStateStopPlayerMessages(itemGuid)
|
||||
}
|
||||
|
||||
private def fireStateStopWhenMounted(tool: Tool, itemGuid: PlanetSideGUID): Unit = {
|
||||
fireStateStopUpdateChargeAndCleanup(tool)
|
||||
fireStateStopMountedMessages(itemGuid)
|
||||
}
|
||||
|
||||
/*
|
||||
used by ReloadMessage handling
|
||||
*/
|
||||
private def reloadPlayerMessages(itemGuid: PlanetSideGUID): Unit = {
|
||||
continent.AvatarEvents ! AvatarServiceMessage(
|
||||
continent.id,
|
||||
AvatarAction.Reload(player.GUID, itemGuid)
|
||||
)
|
||||
}
|
||||
|
||||
private def reloadVehicleMessages(itemGuid: PlanetSideGUID): Unit = {
|
||||
continent.VehicleEvents ! VehicleServiceMessage(
|
||||
continent.id,
|
||||
VehicleAction.Reload(player.GUID, itemGuid)
|
||||
)
|
||||
}
|
||||
|
||||
private def handleReloadProcedure(
|
||||
itemGuid: PlanetSideGUID,
|
||||
obj: PlanetSideGameObject with Container,
|
||||
tools: Set[Tool],
|
||||
unk1: Int,
|
||||
deleteFunc: Equipment => Future[Any],
|
||||
modifyFunc: (AmmoBox, Int) => Unit,
|
||||
messageFunc: PlanetSideGUID => Unit
|
||||
): Unit = {
|
||||
tools
|
||||
.filter { _.GUID == itemGuid }
|
||||
.foreach { tool =>
|
||||
val currentMagazine : Int = tool.Magazine
|
||||
val magazineSize : Int = tool.MaxMagazine
|
||||
val reloadValue : Int = magazineSize - currentMagazine
|
||||
if (magazineSize > 0 && reloadValue > 0) {
|
||||
FindEquipmentStock(obj, FindAmmoBoxThatUses(tool.AmmoType), reloadValue, CountAmmunition).reverse match {
|
||||
case Nil => ()
|
||||
case x :: xs =>
|
||||
xs.foreach { item => deleteFunc(item.obj) }
|
||||
val box = x.obj.asInstanceOf[AmmoBox]
|
||||
val tailReloadValue : Int = if (xs.isEmpty) {
|
||||
0
|
||||
}
|
||||
else {
|
||||
xs.map(_.obj.asInstanceOf[AmmoBox].Capacity).sum
|
||||
}
|
||||
val sumReloadValue : Int = box.Capacity + tailReloadValue
|
||||
val actualReloadValue = if (sumReloadValue <= reloadValue) {
|
||||
deleteFunc(box)
|
||||
sumReloadValue
|
||||
}
|
||||
else {
|
||||
modifyFunc(box, reloadValue - tailReloadValue)
|
||||
reloadValue
|
||||
}
|
||||
val finalReloadValue = actualReloadValue + currentMagazine
|
||||
log.info(
|
||||
s"${player.Name} successfully reloaded $reloadValue ${tool.AmmoType} into ${tool.Definition.Name}"
|
||||
)
|
||||
tool.Magazine = finalReloadValue
|
||||
sendResponse(ReloadMessage(itemGuid, finalReloadValue, unk1))
|
||||
messageFunc(itemGuid)
|
||||
}
|
||||
} else {
|
||||
//the weapon can not reload due to full magazine; the UI for the magazine is obvious bugged, so fix it
|
||||
sendResponse(QuantityUpdateMessage(tool.AmmoSlot.Box.GUID, magazineSize))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private def handleReloadWhenPlayer(
|
||||
itemGuid: PlanetSideGUID,
|
||||
obj: Player,
|
||||
tools: Set[Tool],
|
||||
unk1: Int
|
||||
): Unit = {
|
||||
handleReloadProcedure(
|
||||
itemGuid,
|
||||
obj,
|
||||
tools,
|
||||
unk1,
|
||||
RemoveOldEquipmentFromInventory(obj)(_),
|
||||
ModifyAmmunition(obj)(_, _),
|
||||
reloadPlayerMessages
|
||||
)
|
||||
}
|
||||
|
||||
private def handleReloadWhenMountable(
|
||||
itemGuid: PlanetSideGUID,
|
||||
obj: PlanetSideServerObject with Container,
|
||||
tools: Set[Tool],
|
||||
unk1: Int
|
||||
): Unit = {
|
||||
handleReloadProcedure(
|
||||
itemGuid,
|
||||
obj,
|
||||
tools,
|
||||
unk1,
|
||||
RemoveOldEquipmentFromInventory(obj)(_),
|
||||
ModifyAmmunitionInMountable(obj)(_, _),
|
||||
reloadVehicleMessages
|
||||
)
|
||||
}
|
||||
|
||||
override protected[session] def stop(): Unit = {
|
||||
if (player != null && player.HasGUID) {
|
||||
(prefire ++ shooting).foreach { guid =>
|
||||
continent.AvatarEvents ! AvatarServiceMessage(
|
||||
continent.id,
|
||||
AvatarAction.ChangeFireState_Stop(player.GUID, guid)
|
||||
)
|
||||
//do I need to do this? (maybe)
|
||||
fireStateStopPlayerMessages(guid)
|
||||
fireStateStopMountedMessages(guid)
|
||||
}
|
||||
projectiles.indices.foreach { projectiles.update(_, None) }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8156,7 +8156,7 @@ object GlobalDefinitions {
|
|||
lightgunship.DrownAtMaxDepth = true
|
||||
lightgunship.MaxDepth = 2 //flying vehicles will automatically disable
|
||||
lightgunship.Geometry = GeometryForm.representByCylinder(radius = 2.375f, height = 1.98438f)
|
||||
lightgunship.collision.avatarCollisionDamageMax = 750
|
||||
lightgunship.collision.avatarCollisionDamageMax = 75
|
||||
lightgunship.collision.xy = CollisionXYData(Array((0.1f, 1), (0.25f, 60), (0.5f, 120), (0.75f, 180), (1f, 250)))
|
||||
lightgunship.collision.z = CollisionZData(Array((3f, 1), (9f, 30), (15f, 60), (18f, 90), (19.5f, 125)))
|
||||
lightgunship.maxForwardSpeed = 104f
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ class AvatarService(zone: Zone) extends Actor {
|
|||
|
||||
val AvatarEvents = new GenericEventBus[AvatarServiceResponse] //AvatarEventBus
|
||||
|
||||
def receive = {
|
||||
def receive: Receive = {
|
||||
case Service.Join(channel) =>
|
||||
val path = s"/$channel/Avatar"
|
||||
val who = sender()
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ class VehicleService(zone: Zone) extends Actor {
|
|||
|
||||
val VehicleEvents = new GenericEventBus[VehicleServiceResponse]
|
||||
|
||||
def receive = {
|
||||
def receive: Receive = {
|
||||
case Service.Join(channel) =>
|
||||
val path = s"/$channel/Vehicle"
|
||||
VehicleEvents.subscribe(sender(), path)
|
||||
|
|
@ -33,6 +33,26 @@ class VehicleService(zone: Zone) extends Actor {
|
|||
|
||||
case VehicleServiceMessage(forChannel, action) =>
|
||||
action match {
|
||||
case VehicleAction.ChangeAmmo(player_guid, weapon_guid, weapon_slot, old_ammo_guid, ammo_id, ammo_guid, ammo_data) =>
|
||||
VehicleEvents.publish(
|
||||
VehicleServiceResponse(
|
||||
s"/$forChannel/Vehicle",
|
||||
player_guid,
|
||||
VehicleResponse.ChangeAmmo(weapon_guid, weapon_slot, old_ammo_guid, ammo_id, ammo_guid, ammo_data)
|
||||
)
|
||||
)
|
||||
case VehicleAction.ChangeFireState_Start(player_guid, weapon_guid) =>
|
||||
VehicleEvents.publish(
|
||||
VehicleServiceResponse(
|
||||
s"/$forChannel/Vehicle",
|
||||
player_guid,
|
||||
VehicleResponse.ChangeFireState_Start(weapon_guid)
|
||||
)
|
||||
)
|
||||
case VehicleAction.ChangeFireState_Stop(player_guid, weapon_guid) =>
|
||||
VehicleEvents.publish(
|
||||
VehicleServiceResponse(s"/$forChannel/Vehicle", player_guid, VehicleResponse.ChangeFireState_Stop(weapon_guid))
|
||||
)
|
||||
case VehicleAction.ChildObjectState(player_guid, object_guid, pitch, yaw) =>
|
||||
VehicleEvents.publish(
|
||||
VehicleServiceResponse(
|
||||
|
|
@ -176,6 +196,11 @@ class VehicleService(zone: Zone) extends Actor {
|
|||
VehicleResponse.PlanetsideAttribute(target_guid, attribute_type, attribute_value)
|
||||
)
|
||||
)
|
||||
|
||||
case VehicleAction.Reload(player_guid, weapon_guid) =>
|
||||
VehicleEvents.publish(
|
||||
VehicleServiceResponse(s"/$forChannel/Vehicle", player_guid, VehicleResponse.Reload(weapon_guid))
|
||||
)
|
||||
case VehicleAction.SeatPermissions(player_guid, vehicle_guid, seat_group, permission) =>
|
||||
VehicleEvents.publish(
|
||||
VehicleServiceResponse(
|
||||
|
|
@ -199,6 +224,10 @@ class VehicleService(zone: Zone) extends Actor {
|
|||
)
|
||||
)
|
||||
)
|
||||
case VehicleAction.WeaponDryFire(player_guid, weapon_guid) =>
|
||||
VehicleEvents.publish(
|
||||
VehicleServiceResponse(s"/$forChannel/Vehicle", player_guid, VehicleResponse.WeaponDryFire(weapon_guid))
|
||||
)
|
||||
case VehicleAction.UnloadVehicle(player_guid, vehicle, vehicle_guid) =>
|
||||
VehicleEvents.publish(
|
||||
VehicleServiceResponse(
|
||||
|
|
|
|||
|
|
@ -23,6 +23,17 @@ object VehicleServiceMessage {
|
|||
object VehicleAction {
|
||||
trait Action
|
||||
|
||||
final case class ChangeAmmo(
|
||||
player_guid: PlanetSideGUID,
|
||||
weapon_guid: PlanetSideGUID,
|
||||
weapon_slot: Int,
|
||||
old_ammo_guid: PlanetSideGUID,
|
||||
ammo_id: Int,
|
||||
ammo_guid: PlanetSideGUID,
|
||||
ammo_data: ConstructorData
|
||||
) extends Action
|
||||
final case class ChangeFireState_Start(player_guid: PlanetSideGUID, weapon_guid: PlanetSideGUID) extends Action
|
||||
final case class ChangeFireState_Stop(player_guid: PlanetSideGUID, weapon_guid: PlanetSideGUID) extends Action
|
||||
final case class ChildObjectState(player_guid: PlanetSideGUID, object_guid: PlanetSideGUID, pitch: Float, yaw: Float)
|
||||
extends Action
|
||||
final case class DeployRequest(
|
||||
|
|
@ -89,6 +100,7 @@ object VehicleAction {
|
|||
attribute_type: Int,
|
||||
attribute_value: Long
|
||||
) extends Action
|
||||
final case class Reload(player_guid: PlanetSideGUID, weapon_guid: PlanetSideGUID) extends Action
|
||||
final case class SeatPermissions(
|
||||
player_guid: PlanetSideGUID,
|
||||
vehicle_guid: PlanetSideGUID,
|
||||
|
|
@ -118,6 +130,7 @@ object VehicleAction {
|
|||
unk6: Boolean
|
||||
) extends Action
|
||||
final case class SendResponse(player_guid: PlanetSideGUID, msg: PlanetSideGamePacket) extends Action
|
||||
final case class WeaponDryFire(player_guid: PlanetSideGUID, weapon_guid: PlanetSideGUID) extends Action
|
||||
final case class UpdateAmsSpawnPoint(zone: Zone) extends Action
|
||||
|
||||
final case class TransferPassengerChannel(
|
||||
|
|
|
|||
|
|
@ -22,6 +22,16 @@ final case class VehicleServiceResponse(
|
|||
object VehicleResponse {
|
||||
trait Response
|
||||
|
||||
final case class ChangeAmmo(
|
||||
weapon_guid: PlanetSideGUID,
|
||||
weapon_slot: Int,
|
||||
old_ammo_guid: PlanetSideGUID,
|
||||
ammo_id: Int,
|
||||
ammo_guid: PlanetSideGUID,
|
||||
ammo_data: ConstructorData
|
||||
) extends Response
|
||||
final case class ChangeFireState_Start(weapon_guid: PlanetSideGUID) extends Response
|
||||
final case class ChangeFireState_Stop(weapon_guid: PlanetSideGUID) extends Response
|
||||
final case class ChildObjectState(object_guid: PlanetSideGUID, pitch: Float, yaw: Float) extends Response
|
||||
final case class ConcealPlayer(player_guid: PlanetSideGUID) extends Response
|
||||
final case class DeployRequest(
|
||||
|
|
@ -66,8 +76,9 @@ object VehicleResponse {
|
|||
final case class Ownership(vehicle_guid: PlanetSideGUID) extends Response
|
||||
final case class PlanetsideAttribute(vehicle_guid: PlanetSideGUID, attribute_type: Int, attribute_value: Long)
|
||||
extends Response
|
||||
final case class RevealPlayer(player_guid: PlanetSideGUID) extends Response
|
||||
final case class SeatPermissions(vehicle_guid: PlanetSideGUID, seat_group: Int, permission: Long) extends Response
|
||||
final case class Reload(weapon_guid: PlanetSideGUID) extends Response
|
||||
final case class RevealPlayer(player_guid: PlanetSideGUID) extends Response
|
||||
final case class SeatPermissions(vehicle_guid: PlanetSideGUID, seat_group: Int, permission: Long) extends Response
|
||||
final case class StowEquipment(
|
||||
vehicle_guid: PlanetSideGUID,
|
||||
slot: Int,
|
||||
|
|
@ -75,6 +86,7 @@ object VehicleResponse {
|
|||
iguid: PlanetSideGUID,
|
||||
idata: ConstructorData
|
||||
) extends Response
|
||||
final case class WeaponDryFire(weapon_guid: PlanetSideGUID) extends Response
|
||||
final case class UnloadVehicle(vehicle: Vehicle, vehicle_guid: PlanetSideGUID) extends Response
|
||||
final case class UnstowEquipment(item_guid: PlanetSideGUID) extends Response
|
||||
final case class VehicleState(
|
||||
|
|
|
|||
Loading…
Reference in a new issue