mirror of
https://github.com/psforever/PSF-LoginServer.git
synced 2026-04-29 16:25:30 +00:00
You Can (Not) Hold (#1034)
* dropping the medical applicator on rejoin logins; not actually a bug fix, but a bug mitigation * narrowing the scope of the guard boolean; correcting an issue with purchase timers
This commit is contained in:
parent
690d7ec948
commit
0b8ff5a4ce
5 changed files with 76 additions and 55 deletions
|
|
@ -1446,9 +1446,8 @@ class AvatarActor(
|
||||||
name,
|
name,
|
||||||
cooldown.toSeconds,
|
cooldown.toSeconds,
|
||||||
item match {
|
item match {
|
||||||
case t: ToolDefinition => GlobalDefinitions.isMaxArms(t)
|
case _: KitDefinition => false
|
||||||
case _: VehicleDefinition => true
|
case _ => true
|
||||||
case _ => false
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
case _ => ;
|
case _ => ;
|
||||||
|
|
@ -2573,9 +2572,8 @@ class AvatarActor(
|
||||||
name,
|
name,
|
||||||
cooldown.toSeconds - secondsSincePurchase,
|
cooldown.toSeconds - secondsSincePurchase,
|
||||||
obj match {
|
obj match {
|
||||||
case t: ToolDefinition => GlobalDefinitions.isMaxArms(t)
|
case _: KitDefinition => false
|
||||||
case _: VehicleDefinition => true
|
case _ => true
|
||||||
case _ => false
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -2591,9 +2589,9 @@ class AvatarActor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def updatePurchaseTimer(name: String, time: Long, isActuallyAMachine: Boolean): Unit = {
|
def updatePurchaseTimer(name: String, time: Long, isNotAMedKit: Boolean): Unit = {
|
||||||
sessionActor ! SessionActor.SendResponse(
|
sessionActor ! SessionActor.SendResponse(
|
||||||
AvatarVehicleTimerMessage(session.get.player.GUID, name, time, isActuallyAMachine)
|
AvatarVehicleTimerMessage(session.get.player.GUID, name, time, isNotAMedKit)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,8 @@ import akka.actor.typed.scaladsl.adapter._
|
||||||
import akka.actor.{ActorContext, ActorRef, Cancellable, typed}
|
import akka.actor.{ActorContext, ActorRef, Cancellable, typed}
|
||||||
import akka.pattern.ask
|
import akka.pattern.ask
|
||||||
import akka.util.Timeout
|
import akka.util.Timeout
|
||||||
|
import net.psforever.login.WorldSession
|
||||||
|
import net.psforever.objects.inventory.InventoryItem
|
||||||
import net.psforever.objects.serverobject.mount.Seat
|
import net.psforever.objects.serverobject.mount.Seat
|
||||||
import net.psforever.objects.serverobject.tube.SpawnTube
|
import net.psforever.objects.serverobject.tube.SpawnTube
|
||||||
import net.psforever.objects.sourcing.{PlayerSource, SourceEntry, VehicleSource}
|
import net.psforever.objects.sourcing.{PlayerSource, SourceEntry, VehicleSource}
|
||||||
|
|
@ -559,19 +561,15 @@ class ZoningOperations(
|
||||||
|
|
||||||
zone.Buildings.foreach({ case (_, building) => initBuilding(continentNumber, building.MapId, building) })
|
zone.Buildings.foreach({ case (_, building) => initBuilding(continentNumber, building.MapId, building) })
|
||||||
sendResponse(ZonePopulationUpdateMessage(continentNumber, 414, 138, popTR, 138, popNC, 138, popVS, 138, popBO))
|
sendResponse(ZonePopulationUpdateMessage(continentNumber, 414, 138, popTR, 138, popNC, 138, popVS, 138, popBO))
|
||||||
|
//TODO should actually not claim that the sanctuary or VR zones are locked by their respective empire
|
||||||
if (continentNumber == 11)
|
if (continentNumber == 11)
|
||||||
sendResponse(
|
sendResponse(ContinentalLockUpdateMessage(continentNumber, PlanetSideEmpire.NC))
|
||||||
ContinentalLockUpdateMessage(continentNumber, PlanetSideEmpire.NC)
|
|
||||||
) // "The NC have captured the NC Sanctuary."
|
|
||||||
else if (continentNumber == 12)
|
else if (continentNumber == 12)
|
||||||
sendResponse(
|
sendResponse(ContinentalLockUpdateMessage(continentNumber, PlanetSideEmpire.TR))
|
||||||
ContinentalLockUpdateMessage(continentNumber, PlanetSideEmpire.TR)
|
|
||||||
) // "The TR have captured the TR Sanctuary."
|
|
||||||
else if (continentNumber == 13)
|
else if (continentNumber == 13)
|
||||||
sendResponse(
|
sendResponse(ContinentalLockUpdateMessage(continentNumber, PlanetSideEmpire.VS))
|
||||||
ContinentalLockUpdateMessage(continentNumber, PlanetSideEmpire.VS)
|
else
|
||||||
) // "The VS have captured the VS Sanctuary."
|
sendResponse(ContinentalLockUpdateMessage(continentNumber, PlanetSideEmpire.NEUTRAL))
|
||||||
else sendResponse(ContinentalLockUpdateMessage(continentNumber, PlanetSideEmpire.NEUTRAL))
|
|
||||||
//CaptureFlagUpdateMessage()
|
//CaptureFlagUpdateMessage()
|
||||||
//VanuModuleUpdateMessage()
|
//VanuModuleUpdateMessage()
|
||||||
//ModuleLimitsMessage()
|
//ModuleLimitsMessage()
|
||||||
|
|
@ -1804,6 +1802,7 @@ class ZoningOperations(
|
||||||
session = session.copy(player = p, avatar = a)
|
session = session.copy(player = p, avatar = a)
|
||||||
sessionData.persist()
|
sessionData.persist()
|
||||||
setupAvatarFunc = AvatarRejoin
|
setupAvatarFunc = AvatarRejoin
|
||||||
|
dropMedicalApplicators(p)
|
||||||
avatarActor ! AvatarActor.ReplaceAvatar(a)
|
avatarActor ! AvatarActor.ReplaceAvatar(a)
|
||||||
avatarLoginResponse(a)
|
avatarLoginResponse(a)
|
||||||
|
|
||||||
|
|
@ -1813,6 +1812,7 @@ class ZoningOperations(
|
||||||
deadState = DeadState.Dead
|
deadState = DeadState.Dead
|
||||||
session = session.copy(player = p, avatar = a)
|
session = session.copy(player = p, avatar = a)
|
||||||
sessionData.persist()
|
sessionData.persist()
|
||||||
|
dropMedicalApplicators(p)
|
||||||
HandleReleaseAvatar(p, inZone)
|
HandleReleaseAvatar(p, inZone)
|
||||||
avatarActor ! AvatarActor.ReplaceAvatar(a)
|
avatarActor ! AvatarActor.ReplaceAvatar(a)
|
||||||
avatarLoginResponse(a)
|
avatarLoginResponse(a)
|
||||||
|
|
@ -1894,8 +1894,12 @@ class ZoningOperations(
|
||||||
}
|
}
|
||||||
|
|
||||||
def handleNewPlayerLoaded(tplayer: Player): Unit = {
|
def handleNewPlayerLoaded(tplayer: Player): Unit = {
|
||||||
//new zone
|
/* new zone, might be on `tplayer.Zone` but should definitely be on `session` */
|
||||||
log.info(s"${tplayer.Name} has spawned into ${session.zone.id}")
|
val zone = session.zone
|
||||||
|
val id = zone.id
|
||||||
|
val map = zone.map
|
||||||
|
val mapName = map.name
|
||||||
|
log.info(s"${tplayer.Name} has spawned into $id")
|
||||||
sessionData.oldRefsMap.clear()
|
sessionData.oldRefsMap.clear()
|
||||||
sessionData.persist = UpdatePersistenceAndRefs
|
sessionData.persist = UpdatePersistenceAndRefs
|
||||||
tplayer.avatar = avatar
|
tplayer.avatar = avatar
|
||||||
|
|
@ -1903,18 +1907,8 @@ class ZoningOperations(
|
||||||
avatarActor ! AvatarActor.CreateImplants()
|
avatarActor ! AvatarActor.CreateImplants()
|
||||||
avatarActor ! AvatarActor.InitializeImplants()
|
avatarActor ! AvatarActor.InitializeImplants()
|
||||||
//LoadMapMessage causes the client to send BeginZoningMessage, eventually leading to SetCurrentAvatar
|
//LoadMapMessage causes the client to send BeginZoningMessage, eventually leading to SetCurrentAvatar
|
||||||
val weaponsEnabled =
|
val weaponsEnabled = !(mapName.equals("map11") || mapName.equals("map12") || mapName.equals("map13"))
|
||||||
session.zone.map.name != "map11" && session.zone.map.name != "map12" && session.zone.map.name != "map13"
|
sendResponse(LoadMapMessage(mapName, id, 40100, 25, weaponsEnabled, map.checksum))
|
||||||
sendResponse(
|
|
||||||
LoadMapMessage(
|
|
||||||
session.zone.map.name,
|
|
||||||
session.zone.id,
|
|
||||||
40100,
|
|
||||||
25,
|
|
||||||
weaponsEnabled,
|
|
||||||
session.zone.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
|
||||||
setupAvatarFunc()
|
setupAvatarFunc()
|
||||||
|
|
@ -1934,7 +1928,7 @@ class ZoningOperations(
|
||||||
} else {
|
} else {
|
||||||
//look for different spawn point in same zone
|
//look for different spawn point in same zone
|
||||||
cluster ! ICS.GetNearbySpawnPoint(
|
cluster ! ICS.GetNearbySpawnPoint(
|
||||||
session.zone.Number,
|
zone.Number,
|
||||||
tplayer,
|
tplayer,
|
||||||
Seq(SpawnGroup.Facility, SpawnGroup.Tower, SpawnGroup.AMS),
|
Seq(SpawnGroup.Facility, SpawnGroup.Tower, SpawnGroup.AMS),
|
||||||
context.self
|
context.self
|
||||||
|
|
@ -1974,6 +1968,25 @@ class ZoningOperations(
|
||||||
|
|
||||||
/* support functions */
|
/* support functions */
|
||||||
|
|
||||||
|
private def dropMedicalApplicators(p: Player): Unit = {
|
||||||
|
WorldSession.DropLeftovers(p)(
|
||||||
|
(p.Holsters().zipWithIndex.collect { case (slot, index) if slot.Equipment.nonEmpty => InventoryItem(slot.Equipment.get, index) } ++
|
||||||
|
p.Inventory.Items ++
|
||||||
|
p.FreeHand.Equipment.flatMap { item => Some(InventoryItem(item, Player.FreeHandSlot)) }.toList)
|
||||||
|
.collect {
|
||||||
|
case entry @ InventoryItem(equipment, index)
|
||||||
|
if equipment.Definition == GlobalDefinitions.medicalapplicator && p.DrawnSlot == index =>
|
||||||
|
p.Slot(index).Equipment = None
|
||||||
|
p.DrawnSlot = Player.HandsDownSlot
|
||||||
|
entry
|
||||||
|
case entry @ InventoryItem(equipment, index)
|
||||||
|
if equipment.Definition == GlobalDefinitions.medicalapplicator =>
|
||||||
|
p.Slot(index).Equipment = None
|
||||||
|
entry
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
def isAcceptableNextSpawnPoint: Boolean = isAcceptableSpawnPoint(nextSpawnPoint)
|
def isAcceptableNextSpawnPoint: Boolean = isAcceptableSpawnPoint(nextSpawnPoint)
|
||||||
|
|
||||||
def isAcceptableSpawnPoint(spawnPoint: SpawnPoint): Boolean = isAcceptableSpawnPoint(Some(spawnPoint))
|
def isAcceptableSpawnPoint(spawnPoint: SpawnPoint): Boolean = isAcceptableSpawnPoint(Some(spawnPoint))
|
||||||
|
|
|
||||||
|
|
@ -959,7 +959,7 @@ object WorldSession {
|
||||||
* @param container the original object that contained the items
|
* @param container the original object that contained the items
|
||||||
* @param drops the items to be dropped on the ground
|
* @param drops the items to be dropped on the ground
|
||||||
*/
|
*/
|
||||||
def DropLeftovers(container: PlanetSideServerObject with Container)(drops: List[InventoryItem]): Unit = {
|
def DropLeftovers(container: PlanetSideServerObject with Container)(drops: Iterable[InventoryItem]): Unit = {
|
||||||
//drop or retire
|
//drop or retire
|
||||||
val zone = container.Zone
|
val zone = container.Zone
|
||||||
val pos = container.Position
|
val pos = container.Position
|
||||||
|
|
|
||||||
|
|
@ -7,10 +7,13 @@ import scodec.Codec
|
||||||
import scodec.codecs._
|
import scodec.codecs._
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param player_guid player guid
|
* @param player_guid player guid
|
||||||
* @param text internal name of the item or vehicle name, e.g., medkit, fury, trhev_antipersonnel
|
* @param text internal name of the item or vehicle name, e.g., medkit, fury, trhev_antipersonnel
|
||||||
* @param time cooldown/delay in seconds
|
* @param time cooldown/delay in seconds
|
||||||
* @param unk `true` for vehicles and max exo-suits; `false` for other items
|
* @param unk unk;
|
||||||
|
* most likely has to do with the visibility of the timer in equipment purchasing;
|
||||||
|
* `false` for kit items;
|
||||||
|
* `true` for almost everything else
|
||||||
*/
|
*/
|
||||||
final case class AvatarVehicleTimerMessage(player_guid: PlanetSideGUID, text: String, time: Long, unk: Boolean)
|
final case class AvatarVehicleTimerMessage(player_guid: PlanetSideGUID, text: String, time: Long, unk: Boolean)
|
||||||
extends PlanetSideGamePacket {
|
extends PlanetSideGamePacket {
|
||||||
|
|
|
||||||
|
|
@ -6,22 +6,29 @@ import scodec.Codec
|
||||||
import scodec.codecs._
|
import scodec.codecs._
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* map_name and nav_map_name should match (unless you want to be lost :))
|
* Dispatched from server to client to instigate a zone change.
|
||||||
*
|
* The client should respond with a `BeginZoningMessage` packet.
|
||||||
* ex:
|
* `map_name` and `zone_id` should correspond or the final product will be disorienting, even if it works.
|
||||||
* map13 & home3 = vs sanc
|
* @param map_name designation of the physical zone;
|
||||||
* map10 & z10 = amerish
|
* determines the (deployment) map screen
|
||||||
* map07 & z7 = esamir
|
* @param zone_id designation of the entirety of the zone;
|
||||||
*/
|
* determines the loading screen
|
||||||
|
* @param unk1 na;
|
||||||
|
* seems to match the initial projectile index (that can be assigned)
|
||||||
|
* @param unk2 na;
|
||||||
|
* seems to match the total number of unique projectile indices (that can be assigned) (before looping)
|
||||||
|
* @param weapons_unlocked live fire is permissible;
|
||||||
|
* restricts all actions instigated by that key bind
|
||||||
|
* @param checksum challenge number so that client can confirm server is using the correct version of this zone
|
||||||
|
*/
|
||||||
final case class LoadMapMessage(
|
final case class LoadMapMessage(
|
||||||
map_name: String,
|
map_name: String,
|
||||||
nav_map_name: String, // Also determines loading screen
|
zone_id: String, // Also determines loading screen
|
||||||
unk1: Int,
|
unk1: Int,
|
||||||
unk2: Long,
|
unk2: Long,
|
||||||
weapons_unlocked: Boolean,
|
weapons_unlocked: Boolean,
|
||||||
checksum: Long
|
checksum: Long
|
||||||
) //?
|
) extends PlanetSideGamePacket {
|
||||||
extends PlanetSideGamePacket {
|
|
||||||
type Packet = LoadMapMessage
|
type Packet = LoadMapMessage
|
||||||
def opcode = GamePacketOpcode.LoadMapMessage
|
def opcode = GamePacketOpcode.LoadMapMessage
|
||||||
def encode = LoadMapMessage.encode(this)
|
def encode = LoadMapMessage.encode(this)
|
||||||
|
|
@ -29,8 +36,8 @@ final case class LoadMapMessage(
|
||||||
|
|
||||||
object LoadMapMessage extends Marshallable[LoadMapMessage] {
|
object LoadMapMessage extends Marshallable[LoadMapMessage] {
|
||||||
implicit val codec: Codec[LoadMapMessage] = (
|
implicit val codec: Codec[LoadMapMessage] = (
|
||||||
("map_name" | PacketHelpers.encodedString) :: // TODO: Implement encodedStringWithLimit
|
("map_name" | PacketHelpers.encodedString) :: // TODO: Implement encodedStringWithLimit
|
||||||
("nav_map_name" | PacketHelpers.encodedString) :: //TODO: Implement encodedStringWithLimit
|
("zone_id" | PacketHelpers.encodedString) :: //TODO: Implement encodedStringWithLimit
|
||||||
("unk1" | uint16L) ::
|
("unk1" | uint16L) ::
|
||||||
("unk2" | uint32L) ::
|
("unk2" | uint32L) ::
|
||||||
("weapons_unlocked" | bool) ::
|
("weapons_unlocked" | bool) ::
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue