Persistence (#337)

* constructed service actor to handle persistence of player on server beyond the reaches of WSA from one login to the next; created in PSLogin, interfaced with and updated in WSA

* for what it's worth, players can be completely logged out of the world after 60s of inactivity, alive Infantry only right now;  some code was removed from WSA to make it accessible to other classes but it's incomparable to the new code; broke, fixed, compromised on the code that handles loadouts, server login time, etc.

* moved another common vehicle function into global space; persistence object for players in vehicles during log-out or relogging in a vehicle

* support for relogging when dead/released/unfound; silenced implant slot setup during character select screen

* tested and commented code for managing player avatar persistence

* clarificaion of WSA postStop

* test fixed

* postStop change to account for WSA being cut short during initialization

* clarification of SquadService logout

* player died during setup; probably a relog

* kill the doppelganger WSA; die when you are actually dead

* created manifest to assist with vehicle gating; vehicle gating now accomodates the persistence model much better

* fixed the test

* fixed initial vehicle seat access permissions; moved a subscription to AvatarService to support persistence

* bug fixes: safer GridInventory collision checks, plus specific exceptions; SessionRouter waits for the account intermediary before allowing itself to be started; WSA - match error colution, and MAX without arm now creates the arm it expects

* adjusted insertion and removal code to make inventory management less prone to partoial insertions of removals; inventory integrity checking code writen, but no plans on implementing it yet
This commit is contained in:
Fate-JH 2020-02-14 10:54:52 -05:00 committed by GitHub
parent 06ef3a08c5
commit 53ecee566a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
29 changed files with 2436 additions and 1239 deletions

View file

@ -11,7 +11,7 @@ import ch.qos.logback.core.joran.spi.JoranException
import ch.qos.logback.core.status._
import ch.qos.logback.core.util.StatusPrinter
import com.typesafe.config.ConfigFactory
import net.psforever.config.{Valid, Invalid}
import net.psforever.config.{Invalid, Valid}
import net.psforever.crypto.CryptoInterface
import net.psforever.objects.zones._
import net.psforever.objects.guid.TaskResolver
@ -19,7 +19,7 @@ import org.slf4j
import org.fusesource.jansi.Ansi._
import org.fusesource.jansi.Ansi.Color._
import services.ServiceManager
import services.account.AccountIntermediaryService
import services.account.{AccountIntermediaryService, AccountPersistenceService}
import services.chat.ChatService
import services.galaxy.GalaxyService
import services.teamwork.SquadService
@ -275,6 +275,7 @@ object PsLogin {
serviceManager ! ServiceManager.Register(Props[GalaxyService], "galaxy")
serviceManager ! ServiceManager.Register(Props[SquadService], "squad")
serviceManager ! ServiceManager.Register(Props(classOf[InterstellarCluster], continentList), "cluster")
serviceManager ! ServiceManager.Register(Props[AccountPersistenceService], "accountPersistence")
logger.info("Initializing loginRouter & worldRouter")
/** Create two actors for handling the login and world server endpoints */

View file

@ -6,8 +6,6 @@ import org.log4s.MDC
import scodec.bits._
import scala.collection.mutable
import MDCContextAware.Implicits._
import akka.actor.MDCContextAware.MdcMsg
import akka.actor.SupervisorStrategy.Stop
import net.psforever.packet.PacketCoding
import net.psforever.packet.control.ConnectionClose
@ -35,10 +33,10 @@ case class SessionPipeline(nameTemplate : String, props : Props)
*
* read() route decrypt
* UDP Socket -----> [Session Router] -----> [Crypto Actor] -----> [Session Actor]
* ^ | ^ | ^ |
* /|\ | /|\ | /|\ |
* | write() | | encrypt | | response |
* +--------------+ +-----------+ +-----------------+
**/
*/
class SessionRouter(role : String, pipeline : List[SessionPipeline]) extends Actor with MDCContextAware {
private[this] val log = org.log4s.getLogger(self.path.name)
@ -57,7 +55,7 @@ class SessionRouter(role : String, pipeline : List[SessionPipeline]) extends Act
override def supervisorStrategy = OneForOneStrategy() { case _ => Stop }
override def preStart = {
log.info(s"SessionRouter started...ready for ${role} sessions")
log.info(s"SessionRouter (for ${role}s) initializing ...")
}
def receive = initializing
@ -65,10 +63,13 @@ class SessionRouter(role : String, pipeline : List[SessionPipeline]) extends Act
def initializing : Receive = {
case Hello() =>
inputRef = sender()
context.become(started)
ServiceManager.serviceManager ! Lookup("accountIntermediary")
case ServiceManager.LookupResult("accountIntermediary", endpoint) =>
accountIntermediary = endpoint
log.info(s"SessionRouter starting; ready for $role sessions")
context.become(started)
case default =>
log.error(s"Unknown message $default. Stopping...")
log.error(s"Unknown or unexpected message $default before being properly started. Stopping completely...")
context.stop(self)
}
@ -77,9 +78,7 @@ class SessionRouter(role : String, pipeline : List[SessionPipeline]) extends Act
}
def started : Receive = {
case ServiceManager.LookupResult("accountIntermediary", endpoint) =>
accountIntermediary = endpoint
case recv @ ReceivedPacket(msg, from) =>
case _ @ ReceivedPacket(msg, from) =>
var session : Session = null
if(!idBySocket.contains(from)) {
@ -92,7 +91,7 @@ class SessionRouter(role : String, pipeline : List[SessionPipeline]) extends Act
if(session.state != Closed()) {
MDC("sessionId") = session.sessionId.toString
log.trace(s"RECV: ${msg} -> ${session.getPipeline.head.path.name}")
log.trace(s"RECV: $msg -> ${session.getPipeline.head.path.name}")
session.receive(RawPacket(msg))
MDC.clear()
}
@ -102,7 +101,7 @@ class SessionRouter(role : String, pipeline : List[SessionPipeline]) extends Act
if(session.isDefined) {
if(session.get.state != Closed()) {
MDC("sessionId") = session.get.sessionId.toString
log.trace(s"SEND: ${msg} -> ${inputRef.path.name}")
log.trace(s"SEND: $msg -> ${inputRef.path.name}")
session.get.send(msg)
MDC.clear()
}
@ -160,7 +159,7 @@ class SessionRouter(role : String, pipeline : List[SessionPipeline]) extends Act
sessionByActor{actor} = session
}
log.info(s"New session ID=${id} from " + address.toString)
log.info(s"New session ID=$id from " + address.toString)
if(role == "Login") {
accountIntermediary ! StoreIPAddress(id, new IPAddress(address))
@ -178,14 +177,14 @@ class SessionRouter(role : String, pipeline : List[SessionPipeline]) extends Act
val session : Session = sessionOption.get
if(graceful) {
for(i <- 0 to 5) {
for(_ <- 0 to 5) {
session.send(closePacket)
}
}
// kill all session specific actors
session.dropSession(graceful)
log.info(s"Dropping session ID=${id} (reason: $reason)")
log.info(s"Dropping session ID=$id (reason: $reason)")
}
def newSessionId = {

File diff suppressed because it is too large Load diff