mirror of
https://github.com/2revoemag/PSF-BotServer.git
synced 2026-07-13 15:34:42 +00:00
incoming control container packet unwinding has been shifted from LSA and WSA to PCA
This commit is contained in:
parent
71173c171b
commit
adb7738268
3 changed files with 109 additions and 134 deletions
|
|
@ -10,6 +10,7 @@ import scodec.bits._
|
||||||
import MDCContextAware.Implicits._
|
import MDCContextAware.Implicits._
|
||||||
import com.github.mauricio.async.db.{Connection, QueryResult, RowData}
|
import com.github.mauricio.async.db.{Connection, QueryResult, RowData}
|
||||||
import com.github.mauricio.async.db.mysql.exceptions.MySQLException
|
import com.github.mauricio.async.db.mysql.exceptions.MySQLException
|
||||||
|
import net.psforever.objects.DefaultCancellable
|
||||||
import net.psforever.types.PlanetSideEmpire
|
import net.psforever.types.PlanetSideEmpire
|
||||||
|
|
||||||
import scala.concurrent.{Await, Future}
|
import scala.concurrent.{Await, Future}
|
||||||
|
|
@ -25,7 +26,7 @@ class LoginSessionActor extends Actor with MDCContextAware {
|
||||||
var leftRef : ActorRef = ActorRef.noSender
|
var leftRef : ActorRef = ActorRef.noSender
|
||||||
var rightRef : ActorRef = ActorRef.noSender
|
var rightRef : ActorRef = ActorRef.noSender
|
||||||
|
|
||||||
var updateServerListTask : Cancellable = LoginSessionActor.DefaultCancellable
|
var updateServerListTask : Cancellable = DefaultCancellable.obj
|
||||||
|
|
||||||
override def postStop() = {
|
override def postStop() = {
|
||||||
if(updateServerListTask != null)
|
if(updateServerListTask != null)
|
||||||
|
|
@ -54,59 +55,22 @@ class LoginSessionActor extends Actor with MDCContextAware {
|
||||||
def Started : Receive = {
|
def Started : Receive = {
|
||||||
case UpdateServerList() =>
|
case UpdateServerList() =>
|
||||||
updateServerList()
|
updateServerList()
|
||||||
case ctrl @ ControlPacket(_, _) =>
|
case ControlPacket(_, ctrl) =>
|
||||||
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)
|
handleControlPkt(ctrl)
|
||||||
case game : PlanetSideGamePacket =>
|
case GamePacket(_, _, game) =>
|
||||||
handleGamePkt(game)
|
handleGamePkt(game)
|
||||||
case default => failWithError(s"Invalid packet class received: $default")
|
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) = {
|
def handleControlPkt(pkt : PlanetSideControlPacket) = {
|
||||||
pkt match {
|
pkt match {
|
||||||
case SlottedMetaPacket(slot, subslot, innerPacket) =>
|
|
||||||
// Meta packets are like TCP packets - then need to be ACKed to the client
|
|
||||||
sendResponse(PacketCoding.CreateControlPacket(SlottedMetaAck(slot, subslot)))
|
|
||||||
|
|
||||||
// Decode the inner packet and handle it or error
|
|
||||||
PacketCoding.DecodePacket(innerPacket).fold({
|
|
||||||
error => log.error(s"Failed to decode inner packet of SlottedMetaPacket: $error")
|
|
||||||
}, {
|
|
||||||
handlePkt(_)
|
|
||||||
})
|
|
||||||
/// TODO: figure out what this is what what it does for the PS client
|
/// TODO: figure out what this is what what it does for the PS client
|
||||||
/// I believe it has something to do with reliable packet transmission and resending
|
/// I believe it has something to do with reliable packet transmission and resending
|
||||||
case sync @ ControlSync(diff, unk, f1, f2, f3, f4, fa, fb) =>
|
case sync @ ControlSync(diff, _, _, _, _, _, fa, fb) =>
|
||||||
log.trace(s"SYNC: $sync")
|
log.trace(s"SYNC: $sync")
|
||||||
|
|
||||||
val serverTick = Math.abs(System.nanoTime().toInt) // limit the size to prevent encoding error
|
val serverTick = Math.abs(System.nanoTime().toInt) // limit the size to prevent encoding error
|
||||||
sendResponse(PacketCoding.CreateControlPacket(ControlSyncResp(diff, serverTick,
|
sendResponse(PacketCoding.CreateControlPacket(ControlSyncResp(diff, serverTick, fa, fb, fb, fa)))
|
||||||
fa, fb, fb, fa)))
|
|
||||||
case MultiPacket(packets) =>
|
|
||||||
|
|
||||||
/// Extract out each of the subpackets in the MultiPacket and handle them or raise a packet error
|
|
||||||
packets.foreach { pkt =>
|
|
||||||
PacketCoding.DecodePacket(pkt).fold({ error =>
|
|
||||||
log.error(s"Failed to decode inner packet of MultiPacket: $error")
|
|
||||||
}, {
|
|
||||||
handlePkt(_)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
case default =>
|
case default =>
|
||||||
log.error(s"Unhandled ControlPacket $default")
|
log.error(s"Unhandled ControlPacket $default")
|
||||||
}
|
}
|
||||||
|
|
@ -119,7 +83,6 @@ class LoginSessionActor extends Actor with MDCContextAware {
|
||||||
// TESTING CODE FOR ACCOUNT LOOKUP
|
// TESTING CODE FOR ACCOUNT LOOKUP
|
||||||
def accountLookup(username : String, password : String) : Boolean = {
|
def accountLookup(username : String, password : String) : Boolean = {
|
||||||
val connection: Connection = DatabaseConnector.getAccountsConnection
|
val connection: Connection = DatabaseConnector.getAccountsConnection
|
||||||
|
|
||||||
Await.result(connection.connect, 5 seconds)
|
Await.result(connection.connect, 5 seconds)
|
||||||
|
|
||||||
// create account
|
// create account
|
||||||
|
|
@ -135,13 +98,13 @@ class LoginSessionActor extends Actor with MDCContextAware {
|
||||||
case Some(resultSet) =>
|
case Some(resultSet) =>
|
||||||
val row : RowData = resultSet.head
|
val row : RowData = resultSet.head
|
||||||
row(0)
|
row(0)
|
||||||
case None => -1
|
case None =>
|
||||||
}
|
-1
|
||||||
)
|
})
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// XXX: remove awaits
|
// XXX: remove awaits
|
||||||
val result = Await.result( mapResult, 5 seconds )
|
Await.result( mapResult, 5 seconds )
|
||||||
return true
|
return true
|
||||||
} catch {
|
} catch {
|
||||||
case e : MySQLException =>
|
case e : MySQLException =>
|
||||||
|
|
@ -151,7 +114,6 @@ class LoginSessionActor extends Actor with MDCContextAware {
|
||||||
} finally {
|
} finally {
|
||||||
connection.disconnect
|
connection.disconnect
|
||||||
}
|
}
|
||||||
|
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -190,22 +152,25 @@ class LoginSessionActor extends Actor with MDCContextAware {
|
||||||
log.info(s"Failed login to account $username")
|
log.info(s"Failed login to account $username")
|
||||||
sendResponse(PacketCoding.CreateGamePacket(0, response))
|
sendResponse(PacketCoding.CreateGamePacket(0, response))
|
||||||
}
|
}
|
||||||
|
|
||||||
case ConnectToWorldRequestMessage(name, _, _, _, _, _, _) =>
|
case ConnectToWorldRequestMessage(name, _, _, _, _, _, _) =>
|
||||||
log.info(s"Connect to world request for '$name'")
|
log.info(s"Connect to world request for '$name'")
|
||||||
|
|
||||||
val response = ConnectToWorldMessage(serverName, serverAddress.getHostString, serverAddress.getPort)
|
val response = ConnectToWorldMessage(serverName, serverAddress.getHostString, serverAddress.getPort)
|
||||||
sendResponse(PacketCoding.CreateGamePacket(0, response))
|
sendResponse(PacketCoding.CreateGamePacket(0, response))
|
||||||
sendResponse(DropSession(sessionId, "user transferring to world"))
|
sendResponse(DropSession(sessionId, "user transferring to world"))
|
||||||
case default => log.debug(s"Unhandled GamePacket $pkt")
|
|
||||||
|
case _ =>
|
||||||
|
log.debug(s"Unhandled GamePacket $pkt")
|
||||||
}
|
}
|
||||||
|
|
||||||
def updateServerList() = {
|
def updateServerList() = {
|
||||||
val msg = VNLWorldStatusMessage("Welcome to PlanetSide! ",
|
val msg = VNLWorldStatusMessage("Welcome to PlanetSide! ",
|
||||||
Vector(
|
Vector(
|
||||||
WorldInformation(serverName, WorldStatus.Up, ServerType.Beta,
|
WorldInformation(
|
||||||
Vector(WorldConnectionInfo(serverAddress)), PlanetSideEmpire.VS)
|
serverName, WorldStatus.Up, ServerType.Beta, Vector(WorldConnectionInfo(serverAddress)), PlanetSideEmpire.VS
|
||||||
))
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
sendResponse(PacketCoding.CreateGamePacket(0, msg))
|
sendResponse(PacketCoding.CreateGamePacket(0, msg))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -216,22 +181,13 @@ class LoginSessionActor extends Actor with MDCContextAware {
|
||||||
|
|
||||||
def sendResponse(cont : Any) = {
|
def sendResponse(cont : Any) = {
|
||||||
log.trace("LOGIN SEND: " + cont)
|
log.trace("LOGIN SEND: " + cont)
|
||||||
|
|
||||||
MDC("sessionId") = sessionId.toString
|
MDC("sessionId") = sessionId.toString
|
||||||
rightRef !> cont
|
rightRef !> cont
|
||||||
}
|
}
|
||||||
|
|
||||||
def sendRawResponse(pkt : ByteVector) = {
|
def sendRawResponse(pkt : ByteVector) = {
|
||||||
log.trace("LOGIN SEND RAW: " + pkt)
|
log.trace("LOGIN SEND RAW: " + pkt)
|
||||||
|
|
||||||
MDC("sessionId") = sessionId.toString
|
MDC("sessionId") = sessionId.toString
|
||||||
rightRef !> RawPacket(pkt)
|
rightRef !> RawPacket(pkt)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
object LoginSessionActor {
|
|
||||||
final val DefaultCancellable = new Cancellable() {
|
|
||||||
def isCancelled : Boolean = true
|
|
||||||
def cancel : Boolean = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ import scodec.Attempt.{Failure, Successful}
|
||||||
import scodec.bits._
|
import scodec.bits._
|
||||||
import org.log4s.MDC
|
import org.log4s.MDC
|
||||||
import MDCContextAware.Implicits._
|
import MDCContextAware.Implicits._
|
||||||
import net.psforever.packet.control.{HandleGamePacket, SlottedMetaPacket}
|
import net.psforever.packet.control._
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* In between the network side and the higher functioning side of the simulation:
|
* In between the network side and the higher functioning side of the simulation:
|
||||||
|
|
@ -30,13 +30,14 @@ import net.psforever.packet.control.{HandleGamePacket, SlottedMetaPacket}
|
||||||
*/
|
*/
|
||||||
class PacketCodingActor extends Actor with MDCContextAware {
|
class PacketCodingActor extends Actor with MDCContextAware {
|
||||||
private var sessionId : Long = 0
|
private var sessionId : Long = 0
|
||||||
private var subslot : Int = 0
|
private var subslotOutbound : Int = 0
|
||||||
|
private var subslotInbound : Int = 0
|
||||||
private var leftRef : ActorRef = ActorRef.noSender
|
private var leftRef : ActorRef = ActorRef.noSender
|
||||||
private var rightRef : ActorRef = ActorRef.noSender
|
private var rightRef : ActorRef = ActorRef.noSender
|
||||||
private[this] val log = org.log4s.getLogger
|
private[this] val log = org.log4s.getLogger
|
||||||
|
|
||||||
override def postStop() = {
|
override def postStop() = {
|
||||||
subslot = 0 //in case this `Actor` restarts
|
subslotOutbound = 0 //in case this `Actor` restarts
|
||||||
super.postStop()
|
super.postStop()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -68,12 +69,13 @@ class PacketCodingActor extends Actor with MDCContextAware {
|
||||||
mtuLimit(msg)
|
mtuLimit(msg)
|
||||||
}
|
}
|
||||||
else {//from network, to LSA, WSA, etc. - decode
|
else {//from network, to LSA, WSA, etc. - decode
|
||||||
PacketCoding.unmarshalPayload(0, msg) match { //TODO is it safe for this to always be 0?
|
UnmarshalInnerPacket(msg, "a packet")
|
||||||
case Successful(packet) =>
|
// PacketCoding.unmarshalPayload(0, msg) match { //TODO is it safe for this to always be 0?
|
||||||
sendResponseRight(packet)
|
// case Successful(packet) =>
|
||||||
case Failure(ex) =>
|
// handlePacketContainer(packet) //sendResponseRight
|
||||||
log.info(s"Failed to marshal a packet: $ex")
|
// case Failure(ex) =>
|
||||||
}
|
// log.info(s"Failed to marshal a packet: $ex")
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
//known elevated packet type
|
//known elevated packet type
|
||||||
case ctrl @ ControlPacket(_, packet) =>
|
case ctrl @ ControlPacket(_, packet) =>
|
||||||
|
|
@ -88,7 +90,7 @@ class PacketCodingActor extends Actor with MDCContextAware {
|
||||||
else { //deprecated; ControlPackets should not be coming from this direction
|
else { //deprecated; ControlPackets should not be coming from this direction
|
||||||
log.warn(s"DEPRECATED CONTROL PACKET SEND: $ctrl")
|
log.warn(s"DEPRECATED CONTROL PACKET SEND: $ctrl")
|
||||||
MDC("sessionId") = sessionId.toString
|
MDC("sessionId") = sessionId.toString
|
||||||
sendResponseRight(ctrl)
|
handlePacketContainer(ctrl) //sendResponseRight
|
||||||
}
|
}
|
||||||
//known elevated packet type
|
//known elevated packet type
|
||||||
case game @ GamePacket(_, _, packet) =>
|
case game @ GamePacket(_, _, packet) =>
|
||||||
|
|
@ -123,15 +125,15 @@ class PacketCodingActor extends Actor with MDCContextAware {
|
||||||
/**
|
/**
|
||||||
* Retrieve the current subslot number.
|
* Retrieve the current subslot number.
|
||||||
* Increment the `subslot` for the next time it is needed.
|
* Increment the `subslot` for the next time it is needed.
|
||||||
* @return a 16u number starting at 0
|
* @return a `16u` number starting at 0
|
||||||
*/
|
*/
|
||||||
def Subslot : Int = {
|
def Subslot : Int = {
|
||||||
if(subslot == 65536) { //TODO what is the actual wrap number?
|
if(subslotOutbound == 65536) { //TODO what is the actual wrap number?
|
||||||
subslot = 0
|
subslotOutbound = 0
|
||||||
subslot
|
subslotOutbound
|
||||||
} else {
|
} else {
|
||||||
val curr = subslot
|
val curr = subslotOutbound
|
||||||
subslot += 1
|
subslotOutbound += 1
|
||||||
curr
|
curr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -177,7 +179,7 @@ class PacketCodingActor extends Actor with MDCContextAware {
|
||||||
PacketCoding.EncodePacket(pkt.packet) match {
|
PacketCoding.EncodePacket(pkt.packet) match {
|
||||||
case Successful(bdata) =>
|
case Successful(bdata) =>
|
||||||
sendResponseLeft(bdata.toByteVector)
|
sendResponseLeft(bdata.toByteVector)
|
||||||
case f @ Failure(_) =>
|
case f : Failure =>
|
||||||
log.error(s"$f")
|
log.error(s"$f")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
@ -193,6 +195,72 @@ class PacketCodingActor extends Actor with MDCContextAware {
|
||||||
leftRef !> RawPacket(cont)
|
leftRef !> RawPacket(cont)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transform data into a container packet and re-submit that container to the process that handles the packet.
|
||||||
|
* @param data the packet data
|
||||||
|
* @param description an explanation of the input `data`
|
||||||
|
*/
|
||||||
|
def UnmarshalInnerPacket(data : ByteVector, description : String) : Unit = {
|
||||||
|
PacketCoding.unmarshalPayload(0, data) match { //TODO is it safe for this to always be 0?
|
||||||
|
case Successful(packet) =>
|
||||||
|
handlePacketContainer(packet)
|
||||||
|
case Failure(ex) =>
|
||||||
|
log.info(s"Failed to unmarshal $description: $ex")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sort and redirect a container packet bound for the server by type of contents.
|
||||||
|
* `GamePacket` objects can just onwards without issue.
|
||||||
|
* `ControlPacket` objects may need to be dequeued.
|
||||||
|
* All other container types are invalid.
|
||||||
|
* @param container the container packet
|
||||||
|
*/
|
||||||
|
def handlePacketContainer(container : PlanetSidePacketContainer) : Unit = {
|
||||||
|
container match {
|
||||||
|
case _ : GamePacket =>
|
||||||
|
sendResponseRight(container)
|
||||||
|
case ControlPacket(_, ctrlPkt) =>
|
||||||
|
handleControlPacket(container, ctrlPkt)
|
||||||
|
case default =>
|
||||||
|
log.warn(s"Invalid packet container class received: ${default.getClass.getName}") //do not spill contents in log
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process a control packet or determine that it does not need to be processed at this level.
|
||||||
|
* Primarily, if the packet is of a type that contains another packet that needs be be unmarshalled,
|
||||||
|
* that/those packet must be unwound.<br>
|
||||||
|
* <br>
|
||||||
|
* The subslot information is used to identify these nested packets after arriving at their destination,
|
||||||
|
* to establish order for sequential packets and relation between divided packets.
|
||||||
|
* @param container the original container packet
|
||||||
|
* @param packet the packet that was extracted from the container
|
||||||
|
*/
|
||||||
|
def handleControlPacket(container : PlanetSidePacketContainer, packet : PlanetSideControlPacket) = {
|
||||||
|
packet match {
|
||||||
|
case SlottedMetaPacket(slot, subslot, innerPacket) =>
|
||||||
|
subslotInbound = subslot
|
||||||
|
self.tell(PacketCoding.CreateControlPacket(SlottedMetaAck(slot, subslot)), rightRef) //will go towards network
|
||||||
|
UnmarshalInnerPacket(innerPacket, "the inner packet of a SlottedMetaPacket")
|
||||||
|
|
||||||
|
case MultiPacket(packets) =>
|
||||||
|
packets.foreach { UnmarshalInnerPacket(_, "the inner packet of a MultiPacket") }
|
||||||
|
|
||||||
|
case MultiPacketEx(packets) =>
|
||||||
|
packets.foreach { UnmarshalInnerPacket(_, "the inner packet of a MultiPacketEx") }
|
||||||
|
|
||||||
|
case RelatedA0(subslot) =>
|
||||||
|
log.error(s"bad subslot data - $subslot; potential disarray")
|
||||||
|
|
||||||
|
case RelatedB0(subslot) =>
|
||||||
|
log.trace(s"good control packet received - subslot data $subslot")
|
||||||
|
|
||||||
|
case _ =>
|
||||||
|
sendResponseRight(container)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Decoded packet going towards the simulation.
|
* Decoded packet going towards the simulation.
|
||||||
* @param cont the packet
|
* @param cont the packet
|
||||||
|
|
|
||||||
|
|
@ -137,10 +137,10 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
galaxy = endpoint
|
galaxy = endpoint
|
||||||
log.info("ID: " + sessionId + " Got galaxy service " + endpoint)
|
log.info("ID: " + sessionId + " Got galaxy service " + endpoint)
|
||||||
|
|
||||||
case ctrl @ ControlPacket(_, _) =>
|
case ControlPacket(_, ctrl) =>
|
||||||
handlePktContainer(ctrl)
|
handleControlPkt(ctrl)
|
||||||
case game @ GamePacket(_, _, _) =>
|
case GamePacket(_, _, pkt) =>
|
||||||
handlePktContainer(game)
|
handleGamePkt(pkt)
|
||||||
// temporary hack to keep the client from disconnecting
|
// temporary hack to keep the client from disconnecting
|
||||||
case PokeClient() =>
|
case PokeClient() =>
|
||||||
sendResponse(KeepAliveMessage())
|
sendResponse(KeepAliveMessage())
|
||||||
|
|
@ -1091,61 +1091,12 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
log.warn(s"Invalid packet class received: $default")
|
log.warn(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 => log.error(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 => log.warn(s"Invalid packet container class received: $default")
|
|
||||||
}
|
|
||||||
|
|
||||||
def handleControlPkt(pkt : PlanetSideControlPacket) = {
|
def handleControlPkt(pkt : PlanetSideControlPacket) = {
|
||||||
pkt match {
|
pkt match {
|
||||||
case SlottedMetaPacket(slot, subslot, innerPacket) =>
|
case sync @ ControlSync(diff, _, _, _, _, _, fa, fb) =>
|
||||||
sendResponse(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.debug(s"SYNC: $sync")
|
log.debug(s"SYNC: $sync")
|
||||||
val serverTick = Math.abs(System.nanoTime().toInt) // limit the size to prevent encoding error
|
val serverTick = Math.abs(System.nanoTime().toInt) // limit the size to prevent encoding error
|
||||||
sendResponse(ControlSyncResp(diff, serverTick, fa, fb, fb, fa))
|
sendResponse(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 MultiPacketEx(packets) =>
|
|
||||||
packets.foreach { pkt =>
|
|
||||||
PacketCoding.DecodePacket(pkt) match {
|
|
||||||
case Failure(e) =>
|
|
||||||
log.error(s"Failed to decode inner packet of MultiPacketEx: $e")
|
|
||||||
case Successful(v) =>
|
|
||||||
handlePkt(v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
case RelatedA0(subslot) =>
|
|
||||||
log.error(s"Client not ready for last control packet with subslot $subslot; potential system disarray")
|
|
||||||
|
|
||||||
case RelatedB0(subslot) =>
|
|
||||||
log.trace(s"Good control packet received $subslot")
|
|
||||||
|
|
||||||
case TeardownConnection(_) =>
|
case TeardownConnection(_) =>
|
||||||
log.info("Good bye")
|
log.info("Good bye")
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue