mirror of
https://github.com/2revoemag/PSF-BotServer.git
synced 2026-01-20 02:24:45 +00:00
165 lines
5.5 KiB
Scala
165 lines
5.5 KiB
Scala
// Copyright (c) 2016 PSForever.net to present
|
|
import java.net.{InetAddress, InetSocketAddress}
|
|
|
|
import akka.actor.{Actor, ActorRef, Cancellable, MDCContextAware}
|
|
import net.psforever.packet.{PlanetSideGamePacket, _}
|
|
import net.psforever.packet.control._
|
|
import net.psforever.packet.game._
|
|
import org.log4s.MDC
|
|
import scodec.Attempt.{Failure, Successful}
|
|
import scodec.bits._
|
|
import MDCContextAware.Implicits._
|
|
import net.psforever.types.PlanetSideEmpire
|
|
|
|
import scala.concurrent.duration._
|
|
import scala.util.Random
|
|
|
|
class LoginSessionActor extends Actor with MDCContextAware {
|
|
private[this] val log = org.log4s.getLogger
|
|
|
|
import scala.concurrent.ExecutionContext.Implicits.global
|
|
private case class UpdateServerList()
|
|
|
|
var sessionId : Long = 0
|
|
var leftRef : ActorRef = ActorRef.noSender
|
|
var rightRef : ActorRef = ActorRef.noSender
|
|
|
|
var updateServerListTask : Cancellable = null
|
|
|
|
override def postStop() = {
|
|
if(updateServerListTask != null)
|
|
updateServerListTask.cancel()
|
|
}
|
|
|
|
def receive = Initializing
|
|
|
|
def Initializing : Receive = {
|
|
case HelloFriend(sessionId, right) =>
|
|
this.sessionId = sessionId
|
|
leftRef = sender()
|
|
rightRef = right.asInstanceOf[ActorRef]
|
|
|
|
context.become(Started)
|
|
case _ =>
|
|
log.error("Unknown message")
|
|
context.stop(self)
|
|
}
|
|
|
|
def Started : Receive = {
|
|
case UpdateServerList() =>
|
|
updateServerList()
|
|
case ctrl @ ControlPacket(_, _) =>
|
|
handlePktContainer(ctrl)
|
|
case game @ GamePacket(_, _, _) =>
|
|
handlePktContainer(game)
|
|
case default => failWithError(s"Invalid packet class received: $default")
|
|
}
|
|
|
|
def handlePkt(pkt : PlanetSidePacket) : Unit = pkt match {
|
|
case ctrl : PlanetSideControlPacket =>
|
|
handleControlPkt(ctrl)
|
|
case game : PlanetSideGamePacket =>
|
|
handleGamePkt(game)
|
|
case default => failWithError(s"Invalid packet class received: $default")
|
|
}
|
|
|
|
def handlePktContainer(pkt : PlanetSidePacketContainer) : Unit = pkt match {
|
|
case ctrl @ ControlPacket(opcode, ctrlPkt) =>
|
|
handleControlPkt(ctrlPkt)
|
|
case game @ GamePacket(opcode, seq, gamePkt) =>
|
|
handleGamePkt(gamePkt)
|
|
case default => failWithError(s"Invalid packet container class received: $default")
|
|
}
|
|
|
|
def handleControlPkt(pkt : PlanetSideControlPacket) = {
|
|
pkt match {
|
|
case SlottedMetaPacket(slot, subslot, innerPacket) =>
|
|
sendResponse(PacketCoding.CreateControlPacket(SlottedMetaAck(slot, subslot)))
|
|
|
|
PacketCoding.DecodePacket(innerPacket) match {
|
|
case Failure(e) =>
|
|
log.error(s"Failed to decode inner packet of SlottedMetaPacket: $e")
|
|
case Successful(v) =>
|
|
handlePkt(v)
|
|
}
|
|
case sync @ ControlSync(diff, unk, f1, f2, f3, f4, fa, fb) =>
|
|
log.trace(s"SYNC: ${sync}")
|
|
|
|
val serverTick = Math.abs(System.nanoTime().toInt) // limit the size to prevent encoding error
|
|
sendResponse(PacketCoding.CreateControlPacket(ControlSyncResp(diff, serverTick,
|
|
fa, fb, fb, fa)))
|
|
case MultiPacket(packets) =>
|
|
packets.foreach { pkt =>
|
|
PacketCoding.DecodePacket(pkt) match {
|
|
case Failure(e) =>
|
|
log.error(s"Failed to decode inner packet of MultiPacket: $e")
|
|
case Successful(v) =>
|
|
handlePkt(v)
|
|
}
|
|
}
|
|
case default =>
|
|
log.debug(s"Unhandled ControlPacket $default")
|
|
}
|
|
}
|
|
|
|
// TODO: move to global configuration or database lookup
|
|
val serverName = "PSForever"
|
|
val serverAddress = new InetSocketAddress(LoginConfig.serverIpAddress.getHostAddress, 51001)
|
|
|
|
def handleGamePkt(pkt : PlanetSideGamePacket) = pkt match {
|
|
case LoginMessage(majorVersion, minorVersion, buildDate, username,
|
|
password, token, revision) =>
|
|
|
|
val clientVersion = s"Client Version: ${majorVersion}.${minorVersion}.${revision}, ${buildDate}"
|
|
|
|
if(token.isDefined)
|
|
log.info(s"New login UN:$username Token:${token.get}. ${clientVersion}")
|
|
else
|
|
log.info(s"New login UN:$username PW:$password. ${clientVersion}")
|
|
|
|
val newToken = token.getOrElse("THISISMYTOKENYES")
|
|
val response = LoginRespMessage(newToken, hex"00000000 18FABE0C 00000000 00000000",
|
|
0, 1, 2, 685276011, username, 10001)
|
|
|
|
sendResponse(PacketCoding.CreateGamePacket(0, response))
|
|
|
|
updateServerListTask = context.system.scheduler.schedule(0 seconds, 2 seconds, self, UpdateServerList())
|
|
case ConnectToWorldRequestMessage(name, _, _, _, _, _, _) =>
|
|
log.info(s"Connect to world request for '${name}'")
|
|
|
|
val response = ConnectToWorldMessage(serverName, serverAddress.getHostString, serverAddress.getPort)
|
|
sendResponse(PacketCoding.CreateGamePacket(0, response))
|
|
sendResponse(DropSession(sessionId, "user transferring to world"))
|
|
case default => log.debug(s"Unhandled GamePacket ${pkt}")
|
|
}
|
|
|
|
def updateServerList() = {
|
|
val msg = VNLWorldStatusMessage("Welcome to PlanetSide! ",
|
|
Vector(
|
|
WorldInformation(serverName, WorldStatus.Up, ServerType.Released,
|
|
Vector(WorldConnectionInfo(serverAddress)), PlanetSideEmpire.VS)
|
|
))
|
|
|
|
sendResponse(PacketCoding.CreateGamePacket(0, msg))
|
|
}
|
|
|
|
def failWithError(error : String) = {
|
|
log.error(error)
|
|
//sendResponse(PacketCoding.CreateControlPacket(ConnectionClose()))
|
|
}
|
|
|
|
def sendResponse(cont : Any) = {
|
|
log.trace("LOGIN SEND: " + cont)
|
|
|
|
MDC("sessionId") = sessionId.toString
|
|
rightRef !> cont
|
|
}
|
|
|
|
def sendRawResponse(pkt : ByteVector) = {
|
|
log.trace("LOGIN SEND RAW: " + pkt)
|
|
|
|
MDC("sessionId") = sessionId.toString
|
|
rightRef !> RawPacket(pkt)
|
|
}
|
|
}
|