Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions src/main/resources/application.conf
Original file line number Diff line number Diff line change
Expand Up @@ -580,6 +580,14 @@ network {

# How many attempts at resolving missing packets with anticipated subslot numbers
in-subslot-missing-attempts = 10

# How many recently-sent reliable SlottedMetaPackets are retained for retransmission.
# When the client requests a resend (RelatedA) of a subslot older than this window, the packet
# has been evicted and cannot be recovered, wedging the client. A zone load bursts a large number
# of reliable ObjectCreate packets, so this must comfortably exceed the biggest single-zone
# burst; frequent zoning is the case that drives the requirement.
# Cost is roughly (length * MTU) bytes of retained packet data per session.
smp-history-length = 1024
}

session {
Expand Down
10 changes: 7 additions & 3 deletions src/main/scala/net/psforever/actors/net/MiddlewareActor.scala
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,7 @@ class MiddlewareActor(
MiddlewareActor.propertyOverrideMessageGuard
)

private val smpHistoryLength: Int = 100
private val smpHistoryLength: Int = Config.app.network.middleware.smpHistoryLength

/** History of created `SlottedMetaPacket`s.
* In case the client does not register receiving a packet by checking against packet subslot index numbers,
Expand Down Expand Up @@ -585,11 +585,15 @@ class MiddlewareActor(

case RelatedA(slot, subslot) =>
val requestedSubslot = subslot - 1
preparedSlottedMetaPackets.find(_.subslot == requestedSubslot) match {
//the history ring is pre-sized and holds null slots until it fills, so the predicate must be null-safe
preparedSlottedMetaPackets.find(p => p != null && p.subslot == requestedSubslot) match {
case Some(_packet) =>
outQueueBundled.enqueue(_packet)
case None if requestedSubslot < acceptedSmpSubslot =>
log.warn(s"Client indicated an smp of slot $slot prior to $subslot that is no longer logged")
log.warn(
s"Client indicated an smp of slot $slot prior to $subslot that is no longer logged " +
s"(retransmit history holds $smpHistoryLength packets; raise network.middleware.smp-history-length if this recurs)"
)
case None =>
log.warn(s"Client indicated an smp of slot $slot prior to $subslot that is not found")
}
Expand Down
10 changes: 8 additions & 2 deletions src/main/scala/net/psforever/actors/session/SessionActor.scala
Original file line number Diff line number Diff line change
Expand Up @@ -230,8 +230,8 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con
logic.general.handleRenewCharSavedTimerMsg()

/* common messages (maybe once every respawn) */
case ICS.SpawnPointResponse(response) =>
data.zoning.handleSpawnPointResponse(response)
case ICS.SpawnPointResponse(response, token) =>
data.zoning.handleSpawnPointResponse(response, token)

case SessionActor.NewPlayerLoaded(tplayer) =>
data.zoning.spawn.handleNewPlayerLoaded(tplayer)
Expand Down Expand Up @@ -298,6 +298,12 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con
case ZoningOperations.AvatarAwardMessageBundle(pkts, delay) =>
data.zoning.spawn.performAvatarAwardMessageDelivery(pkts, delay)

case ZoningOperations.ZoningCountdownTick(runnable) =>
data.zoning.beginZoningCountdown(runnable)

case msg: ZoningOperations.ZoningSpawnPointRespawn =>
data.zoning.spawn.handleZoningSpawnPointRespawn(msg)

case CommonMessages.ProgressEvent(delta, finishedAction, stepAction, tick) =>
data.general.handleProgressChange(delta, finishedAction, stepAction, tick)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,8 @@ class LocalHandlerLogic(val ops: SessionLocalHandlers, implicit val context: Act
zone.Number,
player.Faction,
Seq(SpawnGroup.Facility, SpawnGroup.Tower, SpawnGroup.AMS),
context.self
context.self,
token = sessionLogic.zoning.nextSpawnPointToken()
)
}
}
Expand Down
Loading
Loading