mirror of
https://github.com/psforever/PSF-LoginServer.git
synced 2026-03-05 13:30:24 +00:00
added basic Continent management system as a service; hooked it into WSA, at least as far as home3 is concerned; transferred GUID test functions to continent-level
This commit is contained in:
parent
a4b14e5da4
commit
99b019714b
5 changed files with 215 additions and 40 deletions
|
|
@ -0,0 +1,59 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package net.psforever.objects.continent
|
||||
|
||||
import akka.actor.{ActorContext, ActorRef, Props}
|
||||
import net.psforever.objects.Player
|
||||
import net.psforever.objects.entity.IdentifiableEntity
|
||||
import net.psforever.objects.equipment.Equipment
|
||||
import net.psforever.objects.guid.NumberPoolHub
|
||||
import net.psforever.objects.guid.actor.{NumberPoolAccessorActor, NumberPoolActor}
|
||||
import net.psforever.objects.guid.selector.RandomSelector
|
||||
import net.psforever.objects.guid.source.LimitedNumberSource
|
||||
import net.psforever.packet.game.PlanetSideGUID
|
||||
import net.psforever.types.Vector3
|
||||
|
||||
import scala.collection.mutable.ListBuffer
|
||||
|
||||
class Continent(zoneId : String, map : String) {
|
||||
private var actor = ActorRef.noSender
|
||||
private val guid : NumberPoolHub = new NumberPoolHub(new LimitedNumberSource(65536))
|
||||
private var accessor : ActorRef = ActorRef.noSender
|
||||
|
||||
def Actor(implicit context : ActorContext) : ActorRef = {
|
||||
if(actor == ActorRef.noSender) {
|
||||
actor = context.actorOf(Props(classOf[ContinentActor], this), s"$zoneId-actor")
|
||||
|
||||
val pool = guid.AddPool("pool", (400 to 599).toList)
|
||||
val poolActor = context.actorOf(Props(classOf[NumberPoolActor], pool), name = s"$ZoneId-poolActor")
|
||||
pool.Selector = new RandomSelector
|
||||
accessor = context.actorOf(Props(classOf[NumberPoolAccessorActor], guid, pool, poolActor), s"$ZoneId-accessor")
|
||||
}
|
||||
actor
|
||||
}
|
||||
|
||||
private val equipmentOnGround : ListBuffer[Equipment] = ListBuffer[Equipment]()
|
||||
|
||||
def ZoneId : String = zoneId
|
||||
|
||||
def Map : String = map
|
||||
|
||||
def GUID : ActorRef = accessor
|
||||
|
||||
def GUID(object_guid : PlanetSideGUID) : Option[IdentifiableEntity] = guid(object_guid.guid)
|
||||
|
||||
def EquipmentOnGround : ListBuffer[Equipment] = equipmentOnGround
|
||||
}
|
||||
|
||||
object Continent {
|
||||
final def Nowhere : Continent = { Continent("", "") } //TODO needs overrides
|
||||
|
||||
final case class DropItemOnGround(item : Equipment, pos : Vector3, orient : Vector3)
|
||||
|
||||
final case class GetItemOnGround(player : Player, item_guid : PlanetSideGUID)
|
||||
|
||||
final case class GiveItemFromGround(player : Player, item : Equipment)
|
||||
|
||||
def apply(zoneId : String, map : String) : Continent = {
|
||||
new Continent(zoneId, map)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package net.psforever.objects.continent
|
||||
|
||||
import akka.actor.Actor
|
||||
import net.psforever.objects.equipment.Equipment
|
||||
import net.psforever.packet.game.PlanetSideGUID
|
||||
|
||||
import scala.annotation.tailrec
|
||||
|
||||
class ContinentActor(continent : Continent) extends Actor {
|
||||
private[this] val log = org.log4s.getLogger
|
||||
import Continent._
|
||||
|
||||
def receive : Receive = {
|
||||
case DropItemOnGround(item, pos, orient) =>
|
||||
item.Position = pos
|
||||
item.Orientation = orient
|
||||
continent.EquipmentOnGround += item
|
||||
|
||||
case GetItemOnGround(player, item_guid) =>
|
||||
FindItemOnGround(item_guid) match {
|
||||
case Some(item) =>
|
||||
sender ! GiveItemFromGround(player, item)
|
||||
case None =>
|
||||
log.warn(s"item on ground $item_guid was requested by $player for pickup but was not found")
|
||||
}
|
||||
|
||||
case _ => ;
|
||||
}
|
||||
|
||||
private def FindItemOnGround(item_guid : PlanetSideGUID) : Option[Equipment] = {
|
||||
recursiveFindItemOnGround(continent.EquipmentOnGround.iterator, item_guid) match {
|
||||
case Some(index) =>
|
||||
Some(continent.EquipmentOnGround.remove(index))
|
||||
case None =>
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Shift through objects on the ground to find the location of a specific item.
|
||||
* @param iter an `Iterator` of `Equipment`
|
||||
* @param item_guid the global unique identifier of the piece of `Equipment` being sought
|
||||
* @param index the current position in the array-list structure used to create the `Iterator`
|
||||
* @return the index of the object matching `item_guid`, if found;
|
||||
* `None`, otherwise
|
||||
*/
|
||||
@tailrec private def recursiveFindItemOnGround(iter : Iterator[Equipment], item_guid : PlanetSideGUID, index : Int = 0) : Option[Int] = {
|
||||
if(!iter.hasNext) {
|
||||
None
|
||||
}
|
||||
else {
|
||||
val item : Equipment = iter.next
|
||||
if(item.GUID == item_guid) {
|
||||
Some(index)
|
||||
}
|
||||
else {
|
||||
recursiveFindItemOnGround(iter, item_guid, index + 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package net.psforever.objects.continent
|
||||
|
||||
import akka.actor.Actor
|
||||
|
||||
import scala.annotation.tailrec
|
||||
|
||||
class IntergalacticCluster(continents : List[Continent]) extends Actor {
|
||||
//private[this] val log = org.log4s.getLogger
|
||||
for(continent <- continents) {
|
||||
continent.Actor //seed context
|
||||
}
|
||||
|
||||
def receive : Receive = {
|
||||
case IntergalacticCluster.GetWorld(zoneId) =>
|
||||
findWorldInCluster(continents.iterator, zoneId) match {
|
||||
case Some(continent) =>
|
||||
sender ! IntergalacticCluster.GiveWorld(zoneId, continent)
|
||||
case None =>
|
||||
sender ! IntergalacticCluster.GiveWorld(zoneId, Continent.Nowhere)
|
||||
}
|
||||
|
||||
case _ => ;
|
||||
}
|
||||
|
||||
@tailrec private def findWorldInCluster(iter : Iterator[Continent], zoneId : String) : Option[Continent] = {
|
||||
if(!iter.hasNext) {
|
||||
None
|
||||
}
|
||||
else {
|
||||
val cont = iter.next
|
||||
if(cont.ZoneId == zoneId) {
|
||||
Some(cont)
|
||||
}
|
||||
else {
|
||||
findWorldInCluster(iter, zoneId)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
object IntergalacticCluster {
|
||||
final case class GetWorld(zoneId : String)
|
||||
|
||||
final case class GiveWorld(zoneId : String, zone : Continent)
|
||||
}
|
||||
|
|
@ -12,10 +12,8 @@ import ch.qos.logback.core.status._
|
|||
import ch.qos.logback.core.util.StatusPrinter
|
||||
import com.typesafe.config.ConfigFactory
|
||||
import net.psforever.crypto.CryptoInterface
|
||||
import net.psforever.objects.guid.{NumberPoolHub, TaskResolver}
|
||||
import net.psforever.objects.guid.actor.{NumberPoolAccessorActor, NumberPoolActor}
|
||||
import net.psforever.objects.guid.selector.RandomSelector
|
||||
import net.psforever.objects.guid.source.LimitedNumberSource
|
||||
import net.psforever.objects.continent.{Continent, IntergalacticCluster}
|
||||
import net.psforever.objects.guid.TaskResolver
|
||||
import org.slf4j
|
||||
import org.fusesource.jansi.Ansi._
|
||||
import org.fusesource.jansi.Ansi.Color._
|
||||
|
|
@ -89,7 +87,7 @@ object PsLogin {
|
|||
configurator.doConfigure(logfile)
|
||||
}
|
||||
catch {
|
||||
case je : JoranException => ;
|
||||
case _ : JoranException => ;
|
||||
}
|
||||
|
||||
if(loggerHasErrors(lc)) {
|
||||
|
|
@ -202,23 +200,9 @@ object PsLogin {
|
|||
*/
|
||||
|
||||
val serviceManager = ServiceManager.boot
|
||||
|
||||
//experimental guid code
|
||||
val hub = new NumberPoolHub(new LimitedNumberSource(65536))
|
||||
val pool1 = hub.AddPool("test1", (400 to 599).toList)
|
||||
val poolActor1 = system.actorOf(Props(classOf[NumberPoolActor], pool1), name = "poolActor1")
|
||||
pool1.Selector = new RandomSelector
|
||||
val pool2 = hub.AddPool("test2", (600 to 799).toList)
|
||||
val poolActor2 = system.actorOf(Props(classOf[NumberPoolActor], pool2), name = "poolActor2")
|
||||
pool2.Selector = new RandomSelector
|
||||
|
||||
serviceManager ! ServiceManager.Register(Props(classOf[NumberPoolAccessorActor], hub, pool1, poolActor1), "accessor1")
|
||||
serviceManager ! ServiceManager.Register(Props(classOf[NumberPoolAccessorActor], hub, pool2, poolActor2), "accessor2")
|
||||
|
||||
//task resolver
|
||||
serviceManager ! ServiceManager.Register(RandomPool(50).props(Props[TaskResolver]), "taskResolver")
|
||||
|
||||
serviceManager ! ServiceManager.Register(Props[AvatarService], "avatar")
|
||||
serviceManager ! ServiceManager.Register(Props(classOf[IntergalacticCluster], createContinents()), "galaxy")
|
||||
|
||||
/** Create two actors for handling the login and world server endpoints */
|
||||
loginRouter = Props(new SessionRouter("Login", loginTemplate))
|
||||
|
|
@ -235,6 +219,10 @@ object PsLogin {
|
|||
}
|
||||
}
|
||||
|
||||
def createContinents() : List[Continent] = {
|
||||
Continent("home3","map13") :: Nil
|
||||
}
|
||||
|
||||
def main(args : Array[String]) : Unit = {
|
||||
Locale.setDefault(Locale.US); // to have floats with dots, not comma...
|
||||
this.args = args
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import org.log4s.MDC
|
|||
import MDCContextAware.Implicits._
|
||||
import ServiceManager.Lookup
|
||||
import net.psforever.objects._
|
||||
import net.psforever.objects.continent.{Continent, IntergalacticCluster}
|
||||
import net.psforever.objects.entity.IdentifiableEntity
|
||||
import net.psforever.objects.equipment._
|
||||
import net.psforever.objects.guid.{Task, TaskResolver}
|
||||
|
|
@ -24,21 +25,16 @@ import scala.annotation.tailrec
|
|||
import scala.util.Success
|
||||
|
||||
class WorldSessionActor extends Actor with MDCContextAware {
|
||||
import WorldSessionActor._
|
||||
private[this] val log = org.log4s.getLogger
|
||||
|
||||
private final case class PokeClient()
|
||||
private final case class ServerLoaded()
|
||||
private final case class PlayerLoaded(tplayer : Player)
|
||||
private final case class ListAccountCharacters()
|
||||
private final case class SetCurrentAvatar(tplayer : Player)
|
||||
private final case class Continent_GiveItemFromGround(tplyaer : Player, item : Option[Equipment]) //TODO wrong place, move later
|
||||
|
||||
var sessionId : Long = 0
|
||||
var leftRef : ActorRef = ActorRef.noSender
|
||||
var rightRef : ActorRef = ActorRef.noSender
|
||||
var avatarService = Actor.noSender
|
||||
var accessor = Actor.noSender
|
||||
var taskResolver = Actor.noSender
|
||||
var galaxy = Actor.noSender
|
||||
var continent : Continent = Continent.Nowhere
|
||||
|
||||
var clientKeepAlive : Cancellable = WorldSessionActor.DefaultCancellable
|
||||
|
||||
|
|
@ -71,8 +67,8 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
}
|
||||
context.become(Started)
|
||||
ServiceManager.serviceManager ! Lookup("avatar")
|
||||
ServiceManager.serviceManager ! Lookup("accessor1")
|
||||
ServiceManager.serviceManager ! Lookup("taskResolver")
|
||||
ServiceManager.serviceManager ! Lookup("galaxy")
|
||||
|
||||
case _ =>
|
||||
log.error("Unknown message")
|
||||
|
|
@ -83,12 +79,12 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
case ServiceManager.LookupResult("avatar", endpoint) =>
|
||||
avatarService = endpoint
|
||||
log.info("ID: " + sessionId + " Got avatar service " + endpoint)
|
||||
case ServiceManager.LookupResult("accessor1", endpoint) =>
|
||||
accessor = endpoint
|
||||
log.info("ID: " + sessionId + " Got guid service " + endpoint)
|
||||
case ServiceManager.LookupResult("taskResolver", endpoint) =>
|
||||
taskResolver = endpoint
|
||||
log.info("ID: " + sessionId + " Got task resolver service " + endpoint)
|
||||
case ServiceManager.LookupResult("galaxy", endpoint) =>
|
||||
galaxy = endpoint
|
||||
log.info("ID: " + sessionId + " Got galaxy service " + endpoint)
|
||||
|
||||
case ctrl @ ControlPacket(_, _) =>
|
||||
handlePktContainer(ctrl)
|
||||
|
|
@ -413,6 +409,11 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
|
||||
sendResponse(PacketCoding.CreateGamePacket(0, CharacterInfoMessage(0, PlanetSideZoneID(1), 0, PlanetSideGUID(0), true, 0)))
|
||||
|
||||
case IntergalacticCluster.GiveWorld(zoneId, zone) =>
|
||||
player.Continent = zoneId
|
||||
continent = zone
|
||||
taskResolver ! RegisterAvatar(player)
|
||||
|
||||
case PlayerLoaded(tplayer) =>
|
||||
log.info(s"Player $tplayer has been loaded")
|
||||
//init for whole server
|
||||
|
|
@ -456,6 +457,18 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
avatarService ! AvatarServiceMessage(tplayer.Continent, AvatarAction.LoadPlayer(tplayer.GUID, tplayer.Definition.Packet.ConstructorData(tplayer).get))
|
||||
log.debug(s"ObjectCreateDetailedMessage: ${tplayer.Definition.Packet.DetailedConstructorData(tplayer).get}")
|
||||
|
||||
case PlayerFailedToLoad(tplayer) =>
|
||||
player.Continent match {
|
||||
case "tzshvs" =>
|
||||
failWithError(s"$tplayer failed to load anywhere")
|
||||
case "tzdrvs" =>
|
||||
galaxy ! IntergalacticCluster.GetWorld("tzshvs")
|
||||
case "home3" =>
|
||||
galaxy ! IntergalacticCluster.GetWorld("tzdrvs")
|
||||
case _ =>
|
||||
galaxy ! IntergalacticCluster.GetWorld("home3")
|
||||
}
|
||||
|
||||
case SetCurrentAvatar(tplayer) =>
|
||||
//avatar-specific
|
||||
val guid = tplayer.GUID
|
||||
|
|
@ -488,7 +501,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
sendResponse(pkt)
|
||||
|
||||
case default =>
|
||||
failWithError(s"Invalid packet class received: $default")
|
||||
log.warn(s"Invalid packet class received: $default")
|
||||
}
|
||||
|
||||
def handlePkt(pkt : PlanetSidePacket) : Unit = pkt match {
|
||||
|
|
@ -496,7 +509,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
handleControlPkt(ctrl)
|
||||
case game : PlanetSideGamePacket =>
|
||||
handleGamePkt(game)
|
||||
case default => failWithError(s"Invalid packet class received: $default")
|
||||
case default => log.error(s"Invalid packet class received: $default")
|
||||
}
|
||||
|
||||
def handlePktContainer(pkt : PlanetSidePacketContainer) : Unit = pkt match {
|
||||
|
|
@ -504,7 +517,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
handleControlPkt(ctrlPkt)
|
||||
case game @ GamePacket(opcode, seq, gamePkt) =>
|
||||
handleGamePkt(gamePkt)
|
||||
case default => failWithError(s"Invalid packet container class received: $default")
|
||||
case default => log.warn(s"Invalid packet container class received: $default")
|
||||
}
|
||||
|
||||
def handleControlPkt(pkt : PlanetSideControlPacket) = {
|
||||
|
|
@ -667,7 +680,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
//check can spawn on last continent/location from player
|
||||
//if yes, get continent guid accessors
|
||||
//if no, get sanctuary guid accessors and reset the player's expectations
|
||||
taskResolver ! RegisterAvatar(player)
|
||||
galaxy ! IntergalacticCluster.GetWorld("home3")
|
||||
|
||||
import scala.concurrent.duration._
|
||||
import scala.concurrent.ExecutionContext.Implicits.global
|
||||
|
|
@ -1181,7 +1194,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
TaskResolver.GiveTask(
|
||||
new Task() {
|
||||
private val localObject = obj
|
||||
private val localAccessor = accessor
|
||||
private val localAccessor = continent.GUID
|
||||
|
||||
override def isComplete : Task.Resolution.Value = {
|
||||
try {
|
||||
|
|
@ -1316,7 +1329,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
TaskResolver.GiveTask(
|
||||
new Task() {
|
||||
private val localObject = obj
|
||||
private val localAccessor = accessor
|
||||
private val localAccessor = continent.GUID
|
||||
|
||||
override def isComplete : Task.Resolution.Value = {
|
||||
try {
|
||||
|
|
@ -1561,7 +1574,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
|
||||
def failWithError(error : String) = {
|
||||
log.error(error)
|
||||
//sendResponse(PacketCoding.CreateControlPacket(ConnectionClose()))
|
||||
sendResponse(PacketCoding.CreateControlPacket(ConnectionClose()))
|
||||
}
|
||||
|
||||
def sendResponse(cont : PlanetSidePacketContainer) : Unit = {
|
||||
|
|
@ -1581,7 +1594,14 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
}
|
||||
|
||||
object WorldSessionActor {
|
||||
final case class ResponseToSelf(pkt : GamePacket)
|
||||
private final case class ResponseToSelf(pkt : GamePacket)
|
||||
private final case class PokeClient()
|
||||
private final case class ServerLoaded()
|
||||
private final case class PlayerLoaded(tplayer : Player)
|
||||
private final case class PlayerFailedToLoad(tplayer : Player)
|
||||
private final case class ListAccountCharacters()
|
||||
private final case class SetCurrentAvatar(tplayer : Player)
|
||||
private final case class Continent_GiveItemFromGround(tplyaer : Player, item : Option[Equipment]) //TODO wrong place, move later
|
||||
|
||||
/**
|
||||
* A placeholder `Cancellable` object.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue