mirror of
https://github.com/2revoemag/PSF-BotServer.git
synced 2026-07-13 23:44:40 +00:00
automated doors, IFF locks, and bases thus that only permissible doors can be opened by players of correct faction alignment; Base is just a prototype example, hastily created for this functionality; LocalService will eventually be used for doors messages (and other things)
This commit is contained in:
parent
fa633aa79d
commit
7fcac7fc25
16 changed files with 366 additions and 93 deletions
|
|
@ -3,11 +3,16 @@ package net.psforever.objects
|
||||||
|
|
||||||
import net.psforever.objects.definition._
|
import net.psforever.objects.definition._
|
||||||
import net.psforever.objects.definition.converter.{CommandDetonaterConverter, LockerContainerConverter, REKConverter}
|
import net.psforever.objects.definition.converter.{CommandDetonaterConverter, LockerContainerConverter, REKConverter}
|
||||||
|
import net.psforever.objects.doors.{DoorDefinition, IFFLockDefinition}
|
||||||
import net.psforever.objects.equipment.CItem.DeployedItem
|
import net.psforever.objects.equipment.CItem.DeployedItem
|
||||||
import net.psforever.objects.equipment._
|
import net.psforever.objects.equipment._
|
||||||
import net.psforever.objects.inventory.InventoryTile
|
import net.psforever.objects.inventory.InventoryTile
|
||||||
|
<<<<<<< c5ae9e477ccade5759eac2e9526ba898d0e8f16b
|
||||||
import net.psforever.objects.terminals.{CertTerminalDefinition, OrderTerminalDefinition}
|
import net.psforever.objects.terminals.{CertTerminalDefinition, OrderTerminalDefinition}
|
||||||
import net.psforever.packet.game.objectcreate.ObjectClass
|
import net.psforever.packet.game.objectcreate.ObjectClass
|
||||||
|
=======
|
||||||
|
import net.psforever.objects.terminals.OrderTerminalDefinition
|
||||||
|
>>>>>>> automated doors, IFF locks, and bases thus that only permissible doors can be opened by players of correct faction alignment; Base is just a prototype example, hastily created for this functionality; LocalService will eventually be used for doors messages (and other things)
|
||||||
import net.psforever.types.PlanetSideEmpire
|
import net.psforever.types.PlanetSideEmpire
|
||||||
|
|
||||||
object GlobalDefinitions {
|
object GlobalDefinitions {
|
||||||
|
|
@ -1242,4 +1247,9 @@ object GlobalDefinitions {
|
||||||
order_terminal = new OrderTerminalDefinition
|
order_terminal = new OrderTerminalDefinition
|
||||||
val
|
val
|
||||||
cert_terminal = new CertTerminalDefinition
|
cert_terminal = new CertTerminalDefinition
|
||||||
|
|
||||||
|
val
|
||||||
|
external_lock = new IFFLockDefinition
|
||||||
|
val
|
||||||
|
door = new DoorDefinition
|
||||||
}
|
}
|
||||||
|
|
|
||||||
17
common/src/main/scala/net/psforever/objects/doors/Base.scala
Normal file
17
common/src/main/scala/net/psforever/objects/doors/Base.scala
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
// Copyright (c) 2017 PSForever
|
||||||
|
package net.psforever.objects.doors
|
||||||
|
|
||||||
|
import net.psforever.types.PlanetSideEmpire
|
||||||
|
|
||||||
|
class Base(private val id : Int) {
|
||||||
|
private var faction : PlanetSideEmpire.Value = PlanetSideEmpire.NEUTRAL
|
||||||
|
|
||||||
|
def Id : Int = id
|
||||||
|
|
||||||
|
def Faction : PlanetSideEmpire.Value = faction
|
||||||
|
|
||||||
|
def Faction_=(emp : PlanetSideEmpire.Value) : PlanetSideEmpire.Value = {
|
||||||
|
faction = emp
|
||||||
|
Faction
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -4,7 +4,6 @@ package net.psforever.objects.doors
|
||||||
import akka.actor.{ActorContext, ActorRef, Props}
|
import akka.actor.{ActorContext, ActorRef, Props}
|
||||||
import net.psforever.objects.{PlanetSideGameObject, Player}
|
import net.psforever.objects.{PlanetSideGameObject, Player}
|
||||||
import net.psforever.packet.game.UseItemMessage
|
import net.psforever.packet.game.UseItemMessage
|
||||||
import net.psforever.types.PlanetSideEmpire
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* na
|
* na
|
||||||
|
|
@ -22,26 +21,29 @@ class Door(ddef : DoorDefinition) extends PlanetSideGameObject {
|
||||||
}
|
}
|
||||||
|
|
||||||
private var openState : Boolean = false
|
private var openState : Boolean = false
|
||||||
private var faction : PlanetSideEmpire.Value = PlanetSideEmpire.NEUTRAL
|
private var lockState : Boolean = false
|
||||||
private var hackedBy : Option[PlanetSideEmpire.Value] = None
|
|
||||||
|
|
||||||
def Open : Boolean = openState
|
def Open : Boolean = openState
|
||||||
|
|
||||||
def Faction : PlanetSideEmpire.Value = faction
|
def Open_=(open : Boolean) : Boolean = {
|
||||||
|
openState = open
|
||||||
def Convert(toFaction : PlanetSideEmpire.Value) : Unit = {
|
Open
|
||||||
hackedBy = None
|
|
||||||
faction = toFaction
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def Request(player : Player, msg : UseItemMessage) : Door.Exchange = {
|
def Locked : Boolean = lockState
|
||||||
if(!openState) {
|
|
||||||
if(faction == PlanetSideEmpire.NEUTRAL || player.Faction == faction) {
|
def Locked_=(lock : Boolean) : Boolean = {
|
||||||
Door.OpenEvent()
|
lockState = lock
|
||||||
}
|
Locked
|
||||||
else {
|
}
|
||||||
Door.NoEvent()
|
|
||||||
}
|
def Use(player : Player, msg : UseItemMessage) : Door.Exchange = {
|
||||||
|
if(!lockState && !openState) {
|
||||||
|
openState = true
|
||||||
|
Door.OpenEvent()
|
||||||
|
}
|
||||||
|
else if(openState) {
|
||||||
|
Door.CloseEvent()
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Door.NoEvent()
|
Door.NoEvent()
|
||||||
|
|
@ -52,7 +54,7 @@ class Door(ddef : DoorDefinition) extends PlanetSideGameObject {
|
||||||
}
|
}
|
||||||
|
|
||||||
object Door {
|
object Door {
|
||||||
final case class Request(player : Player, msg : UseItemMessage)
|
final case class Use(player : Player, msg : UseItemMessage)
|
||||||
|
|
||||||
sealed trait Exchange
|
sealed trait Exchange
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,8 +11,8 @@ class DoorControl(door : Door) extends Actor {
|
||||||
private var doorCloser : Cancellable = DoorControl.DefaultCloser
|
private var doorCloser : Cancellable = DoorControl.DefaultCloser
|
||||||
|
|
||||||
def receive : Receive = {
|
def receive : Receive = {
|
||||||
case Door.Request(player, msg) =>
|
case Door.Use(player, msg) =>
|
||||||
sender ! Door.DoorMessage(player, msg, door.Request(player, msg))
|
sender ! Door.DoorMessage(player, msg, door.Use(player, msg))
|
||||||
//doorCloser = context.system.scheduler.scheduleOnce(5000L, sender, Door.DoorMessage())
|
//doorCloser = context.system.scheduler.scheduleOnce(5000L, sender, Door.DoorMessage())
|
||||||
case _ =>
|
case _ =>
|
||||||
sender ! Door.NoEvent()
|
sender ! Door.NoEvent()
|
||||||
|
|
|
||||||
|
|
@ -5,9 +5,8 @@ import net.psforever.objects.definition.ObjectDefinition
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The definition for any `door`.
|
* The definition for any `door`.
|
||||||
* @param objectId the object's identifier number
|
* Object Id 242 is a generic door.
|
||||||
*/
|
*/
|
||||||
abstract class DoorDefinition(objectId : Int) extends ObjectDefinition(objectId) {
|
class DoorDefinition extends ObjectDefinition(242) {
|
||||||
Name = "door"
|
Name = "door"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
// Copyright (c) 2017 PSForever
|
||||||
|
package net.psforever.objects.doors
|
||||||
|
|
||||||
|
import net.psforever.objects.{GlobalDefinitions, PlanetSideGameObject}
|
||||||
|
import net.psforever.types.PlanetSideEmpire
|
||||||
|
|
||||||
|
class IFFLock extends PlanetSideGameObject {
|
||||||
|
private var hackedBy : Option[PlanetSideEmpire.Value] = None
|
||||||
|
|
||||||
|
def Hacker : Option[PlanetSideEmpire.Value] = hackedBy
|
||||||
|
|
||||||
|
def Hacker_=(hacker : PlanetSideEmpire.Value) : Option[PlanetSideEmpire.Value] = {
|
||||||
|
Hacker = Some(hacker)
|
||||||
|
}
|
||||||
|
|
||||||
|
def Hacker_=(hacker : Option[PlanetSideEmpire.Value]) : Option[PlanetSideEmpire.Value] = {
|
||||||
|
hackedBy = hacker
|
||||||
|
Hacker
|
||||||
|
}
|
||||||
|
|
||||||
|
def Definition : IFFLockDefinition = GlobalDefinitions.external_lock
|
||||||
|
}
|
||||||
|
|
||||||
|
object IFFLock {
|
||||||
|
def apply() : IFFLock = {
|
||||||
|
new IFFLock
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
// Copyright (c) 2017 PSForever
|
||||||
|
package net.psforever.objects.doors
|
||||||
|
|
||||||
|
import net.psforever.objects.definition.ObjectDefinition
|
||||||
|
|
||||||
|
class IFFLockDefinition extends ObjectDefinition(0) {
|
||||||
|
Name = "iff_lock"
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
// Copyright (c) 2017 PSForever
|
||||||
|
package net.psforever.objects.zones
|
||||||
|
|
||||||
|
import net.psforever.objects.doors.{IFFLock, IFFLockDefinition}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wrapper `Class` designed to instantiate a `Door` server object.
|
||||||
|
* @param idef a `IFFLockDefinition` object, indicating the specific functionality of the resulting `Door`
|
||||||
|
* @param id the globally unique identifier to which this `IFFLock` will be registered
|
||||||
|
*/
|
||||||
|
class IFFLockObjectBuilder(private val idef : IFFLockDefinition, private val id : Int) extends ServerObjectBuilder[IFFLock] {
|
||||||
|
import akka.actor.ActorContext
|
||||||
|
import net.psforever.objects.guid.NumberPoolHub
|
||||||
|
|
||||||
|
def Build(implicit context : ActorContext, guid : NumberPoolHub) : IFFLock = {
|
||||||
|
val obj = IFFLock()
|
||||||
|
guid.register(obj, id) //non-Actor GUID registration
|
||||||
|
obj
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object IFFLockObjectBuilder {
|
||||||
|
/**
|
||||||
|
* Overloaded constructor for a `IFFLockObjectBuilder`.
|
||||||
|
* @param idef an `IFFLock` object
|
||||||
|
* @param id a globally unique identifier
|
||||||
|
* @return an `IFFLockObjectBuilder` object
|
||||||
|
*/
|
||||||
|
def apply(idef : IFFLockDefinition, id : Int) : IFFLockObjectBuilder = {
|
||||||
|
new IFFLockObjectBuilder(idef, id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
package net.psforever.objects.zones
|
package net.psforever.objects.zones
|
||||||
|
|
||||||
import akka.actor.{ActorContext, ActorRef, Props}
|
import akka.actor.{ActorContext, ActorRef, Props}
|
||||||
|
import net.psforever.objects.doors.Base
|
||||||
import net.psforever.objects.{PlanetSideGameObject, Player}
|
import net.psforever.objects.{PlanetSideGameObject, Player}
|
||||||
import net.psforever.objects.equipment.Equipment
|
import net.psforever.objects.equipment.Equipment
|
||||||
import net.psforever.objects.guid.NumberPoolHub
|
import net.psforever.objects.guid.NumberPoolHub
|
||||||
|
|
@ -48,6 +49,8 @@ class Zone(private val zoneId : String, zoneMap : ZoneMap, zoneNumber : Int) {
|
||||||
/** Used by the `Zone` to coordinate `Equipment` dropping and collection requests. */
|
/** Used by the `Zone` to coordinate `Equipment` dropping and collection requests. */
|
||||||
private var ground : ActorRef = ActorRef.noSender
|
private var ground : ActorRef = ActorRef.noSender
|
||||||
|
|
||||||
|
private var bases : List[Base] = List()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Establish the basic accessible conditions necessary for a functional `Zone`.<br>
|
* Establish the basic accessible conditions necessary for a functional `Zone`.<br>
|
||||||
* <br>
|
* <br>
|
||||||
|
|
@ -69,6 +72,8 @@ class Zone(private val zoneId : String, zoneMap : ZoneMap, zoneNumber : Int) {
|
||||||
Map.LocalObjects.foreach({ builderObject =>
|
Map.LocalObjects.foreach({ builderObject =>
|
||||||
builderObject.Build
|
builderObject.Build
|
||||||
})
|
})
|
||||||
|
|
||||||
|
MakeBases(Map.LocalBases)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -169,6 +174,15 @@ class Zone(private val zoneId : String, zoneMap : ZoneMap, zoneNumber : Int) {
|
||||||
*/
|
*/
|
||||||
def Ground : ActorRef = ground
|
def Ground : ActorRef = ground
|
||||||
|
|
||||||
|
def MakeBases(num : Int) : List[Base] = {
|
||||||
|
bases = (0 to num).map(id => new Base(id)).toList
|
||||||
|
bases
|
||||||
|
}
|
||||||
|
|
||||||
|
def Base(id : Int) : Option[Base] = {
|
||||||
|
bases.lift(id)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provide bulk correspondence on all map entities that can be composed into packet messages and reported to a client.
|
* Provide bulk correspondence on all map entities that can be composed into packet messages and reported to a client.
|
||||||
* These messages are sent in this fashion at the time of joining the server:<br>
|
* These messages are sent in this fashion at the time of joining the server:<br>
|
||||||
|
|
|
||||||
|
|
@ -13,8 +13,48 @@ class ZoneActor(zone : Zone) extends Actor {
|
||||||
def receive : Receive = {
|
def receive : Receive = {
|
||||||
case Zone.Init() =>
|
case Zone.Init() =>
|
||||||
zone.Init
|
zone.Init
|
||||||
|
ZoneSetupCheck()
|
||||||
|
|
||||||
case msg =>
|
case msg =>
|
||||||
log.warn(s"Received unexpected message - $msg")
|
log.warn(s"Received unexpected message - $msg")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def ZoneSetupCheck(): Unit = {
|
||||||
|
def guid(id : Int) = zone.GUID(id)
|
||||||
|
val map = zone.Map
|
||||||
|
val slog = org.log4s.getLogger(s"zone/${zone.Id}/sanity")
|
||||||
|
|
||||||
|
//check base to object associations
|
||||||
|
map.ObjectToBase.foreach({ case((object_guid, base_id)) =>
|
||||||
|
if(zone.Base(base_id).isEmpty) {
|
||||||
|
slog.error(s"expected a base #$base_id")
|
||||||
|
}
|
||||||
|
if(guid(object_guid).isEmpty) {
|
||||||
|
slog.error(s"expected object id $object_guid to exist, but it did not")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
//check door to lock association
|
||||||
|
import net.psforever.objects.doors.{Door, IFFLock}
|
||||||
|
map.DoorToLock.foreach({ case((door_guid, lock_guid)) =>
|
||||||
|
try {
|
||||||
|
if(!guid(door_guid).get.isInstanceOf[Door]) {
|
||||||
|
slog.error(s"expected id $door_guid to be a door, but it was not")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
case _ : Exception =>
|
||||||
|
slog.error(s"expected a door, but looking for uninitialized object $door_guid")
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
if(!guid(lock_guid).get.isInstanceOf[IFFLock]) {
|
||||||
|
slog.error(s"expected id $lock_guid to be an IFF lock, but it was not")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
case _ : Exception =>
|
||||||
|
slog.error(s"expected an IFF lock, but looking for uninitialized object $lock_guid")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,19 +12,31 @@ package net.psforever.objects.zones
|
||||||
* Use it as a blueprint.<br>
|
* Use it as a blueprint.<br>
|
||||||
* <br>
|
* <br>
|
||||||
* The "training zones" are the best example of the difference between a `ZoneMap` and a `Zone.`
|
* The "training zones" are the best example of the difference between a `ZoneMap` and a `Zone.`
|
||||||
|
* ("Course" will be used as an unofficial location and layout descriptor.)
|
||||||
* `tzdrtr` is the Terran Republic driving course.
|
* `tzdrtr` is the Terran Republic driving course.
|
||||||
* `tzdrvs` is the Vanu Sovereignty driving course.
|
* `tzdrvs` is the Vanu Sovereignty driving course.
|
||||||
* While each course can have different objects and object states (`Zone`),
|
* While each course can have different objects and object states, i.e., a `Zone`,
|
||||||
* both courses have the same basic server objects because they are built from the same blueprint (`ZoneMap`).
|
* both of these courses utilize the same basic server object layout because they are built from the same blueprint, i.e., a `ZoneMap`.
|
||||||
* @param name the privileged name that can be used as the first parameter in the packet `LoadMapMessage`
|
* @param name the privileged name that can be used as the first parameter in the packet `LoadMapMessage`
|
||||||
* @see `ServerObjectBuilder`<br>
|
* @see `ServerObjectBuilder`<br>
|
||||||
* `LoadMapMessage`
|
* `LoadMapMessage`
|
||||||
*/
|
*/
|
||||||
class ZoneMap(private val name : String) {
|
class ZoneMap(private val name : String) {
|
||||||
private var localObjects : List[ServerObjectBuilder[_]] = List()
|
private var localObjects : List[ServerObjectBuilder[_]] = List()
|
||||||
|
private var linkDoorLock : Map[Int, Int] = Map()
|
||||||
|
private var linkObjectBase : Map[Int, Int] = Map()
|
||||||
|
private var numBases : Int = 0
|
||||||
|
|
||||||
def Name : String = name
|
def Name : String = name
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The list of all server object builder wrappers that have been assigned to this `ZoneMap`.
|
||||||
|
* @return the `List` of all `ServerObjectBuilders` known to this `ZoneMap`
|
||||||
|
*/
|
||||||
|
def LocalObjects : List[ServerObjectBuilder[_]] = {
|
||||||
|
localObjects
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Append the builder for a server object to the list of builders known to this `ZoneMap`.
|
* Append the builder for a server object to the list of builders known to this `ZoneMap`.
|
||||||
* @param obj the builder for a server object
|
* @param obj the builder for a server object
|
||||||
|
|
@ -33,11 +45,22 @@ class ZoneMap(private val name : String) {
|
||||||
localObjects = localObjects :+ obj
|
localObjects = localObjects :+ obj
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
def LocalBases : Int = numBases
|
||||||
* The list of all server object builder wrappers that have been assigned to this `ZoneMap`.
|
|
||||||
* @return the `List` of all `ServerObjectBuilders` known to this `ZoneMap`
|
def LocalBases_=(num : Int) : Int = {
|
||||||
*/
|
numBases = math.max(0, num)
|
||||||
def LocalObjects : List[ServerObjectBuilder[_]] = {
|
LocalBases
|
||||||
localObjects
|
}
|
||||||
|
|
||||||
|
def ObjectToBase : Map[Int, Int] = linkObjectBase
|
||||||
|
|
||||||
|
def ObjectToBase(object_guid : Int, base_id : Int) : Unit = {
|
||||||
|
linkObjectBase = linkObjectBase ++ Map(object_guid -> base_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
def DoorToLock : Map[Int, Int] = linkDoorLock
|
||||||
|
|
||||||
|
def DoorToLock(door_guid : Int, lock_guid : Int) = {
|
||||||
|
linkDoorLock = linkDoorLock ++ Map(door_guid -> lock_guid)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,22 +1,14 @@
|
||||||
// Copyright (c) 2016 PSForever.net to present
|
// Copyright (c) 2017 PSForever
|
||||||
import akka.actor.Actor
|
import akka.actor.Actor
|
||||||
import akka.event.{ActorEventBus, SubchannelClassification}
|
|
||||||
import akka.util.Subclassification
|
|
||||||
import net.psforever.objects.equipment.Equipment
|
import net.psforever.objects.equipment.Equipment
|
||||||
import net.psforever.packet.game.objectcreate.ConstructorData
|
import net.psforever.packet.game.objectcreate.ConstructorData
|
||||||
import net.psforever.types.ExoSuitType
|
import net.psforever.types.ExoSuitType
|
||||||
import net.psforever.packet.game.{PlanetSideGUID, PlayerStateMessageUpstream}
|
import net.psforever.packet.game.{PlanetSideGUID, PlayerStateMessageUpstream}
|
||||||
import net.psforever.types.Vector3
|
import net.psforever.types.Vector3
|
||||||
|
|
||||||
sealed trait Action
|
|
||||||
|
|
||||||
sealed trait Response
|
|
||||||
|
|
||||||
final case class Join(channel : String)
|
|
||||||
final case class Leave()
|
|
||||||
final case class LeaveAll()
|
|
||||||
|
|
||||||
object AvatarAction {
|
object AvatarAction {
|
||||||
|
trait Action
|
||||||
|
|
||||||
final case class ArmorChanged(player_guid : PlanetSideGUID, suit : ExoSuitType.Value, subtype : Int) extends Action
|
final case class ArmorChanged(player_guid : PlanetSideGUID, suit : ExoSuitType.Value, subtype : Int) extends Action
|
||||||
//final case class DropItem(pos : Vector3, orient : Vector3, item : PlanetSideGUID) extends Action
|
//final case class DropItem(pos : Vector3, orient : Vector3, item : PlanetSideGUID) extends Action
|
||||||
final case class EquipmentInHand(player_guid : PlanetSideGUID, slot : Int, item : Equipment) extends Action
|
final case class EquipmentInHand(player_guid : PlanetSideGUID, slot : Int, item : Equipment) extends Action
|
||||||
|
|
@ -36,6 +28,8 @@ object AvatarAction {
|
||||||
}
|
}
|
||||||
|
|
||||||
object AvatarServiceResponse {
|
object AvatarServiceResponse {
|
||||||
|
trait Response
|
||||||
|
|
||||||
final case class ArmorChanged(suit : ExoSuitType.Value, subtype : Int) extends Response
|
final case class ArmorChanged(suit : ExoSuitType.Value, subtype : Int) extends Response
|
||||||
//final case class DropItem(pos : Vector3, orient : Vector3, item : PlanetSideGUID) extends Response
|
//final case class DropItem(pos : Vector3, orient : Vector3, item : PlanetSideGUID) extends Response
|
||||||
final case class EquipmentInHand(slot : Int, item : Equipment) extends Response
|
final case class EquipmentInHand(slot : Int, item : Equipment) extends Response
|
||||||
|
|
@ -54,30 +48,14 @@ object AvatarServiceResponse {
|
||||||
// final case class ChangeWeapon(facingYaw : Int) extends Response
|
// final case class ChangeWeapon(facingYaw : Int) extends Response
|
||||||
}
|
}
|
||||||
|
|
||||||
final case class AvatarServiceMessage(forChannel : String, actionMessage : Action)
|
final case class AvatarServiceMessage(forChannel : String, actionMessage : AvatarAction.Action)
|
||||||
|
|
||||||
final case class AvatarServiceResponse(toChannel : String, avatar_guid : PlanetSideGUID, replyMessage : Response)
|
final case class AvatarServiceResponse(toChannel : String, avatar_guid : PlanetSideGUID, replyMessage : AvatarServiceResponse.Response) extends GenericEventBusMsg
|
||||||
|
|
||||||
/*
|
/*
|
||||||
/avatar/
|
/Avatar/
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class AvatarEventBus extends ActorEventBus with SubchannelClassification {
|
|
||||||
type Event = AvatarServiceResponse
|
|
||||||
type Classifier = String
|
|
||||||
|
|
||||||
protected def classify(event: Event): Classifier = event.toChannel
|
|
||||||
|
|
||||||
protected def subclassification = new Subclassification[Classifier] {
|
|
||||||
def isEqual(x: Classifier, y: Classifier) = x == y
|
|
||||||
def isSubclass(x: Classifier, y: Classifier) = x.startsWith(y)
|
|
||||||
}
|
|
||||||
|
|
||||||
protected def publish(event: Event, subscriber: Subscriber): Unit = {
|
|
||||||
subscriber ! event
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class AvatarService extends Actor {
|
class AvatarService extends Actor {
|
||||||
//import AvatarServiceResponse._
|
//import AvatarServiceResponse._
|
||||||
private [this] val log = org.log4s.getLogger
|
private [this] val log = org.log4s.getLogger
|
||||||
|
|
@ -86,62 +64,58 @@ class AvatarService extends Actor {
|
||||||
log.info("Starting...")
|
log.info("Starting...")
|
||||||
}
|
}
|
||||||
|
|
||||||
val AvatarEvents = new AvatarEventBus
|
val AvatarEvents = new GenericEventBus[AvatarServiceResponse] //AvatarEventBus
|
||||||
|
|
||||||
/*val channelMap = Map(
|
|
||||||
AvatarMessageType.CMT_OPEN -> AvatarPath("local")
|
|
||||||
)*/
|
|
||||||
|
|
||||||
def receive = {
|
def receive = {
|
||||||
case Join(channel) =>
|
case Service.Join(channel) =>
|
||||||
val path = "/Avatar/" + channel
|
val path = s"/$channel/Avatar"
|
||||||
val who = sender()
|
val who = sender()
|
||||||
|
|
||||||
log.info(s"$who has joined $path")
|
log.info(s"$who has joined $path")
|
||||||
|
|
||||||
AvatarEvents.subscribe(who, path)
|
AvatarEvents.subscribe(who, path)
|
||||||
case Leave() =>
|
case Service.Leave() =>
|
||||||
AvatarEvents.unsubscribe(sender())
|
AvatarEvents.unsubscribe(sender())
|
||||||
case LeaveAll() =>
|
case Service.LeaveAll() =>
|
||||||
AvatarEvents.unsubscribe(sender())
|
AvatarEvents.unsubscribe(sender())
|
||||||
|
|
||||||
case AvatarServiceMessage(forChannel, action) =>
|
case AvatarServiceMessage(forChannel, action) =>
|
||||||
action match {
|
action match {
|
||||||
case AvatarAction.ArmorChanged(player_guid, suit, subtype) =>
|
case AvatarAction.ArmorChanged(player_guid, suit, subtype) =>
|
||||||
AvatarEvents.publish(
|
AvatarEvents.publish(
|
||||||
AvatarServiceResponse("/Avatar/" + forChannel, player_guid, AvatarServiceResponse.ArmorChanged(suit, subtype))
|
AvatarServiceResponse(s"/$forChannel/Avatar", player_guid, AvatarServiceResponse.ArmorChanged(suit, subtype))
|
||||||
)
|
)
|
||||||
case AvatarAction.EquipmentInHand(player_guid, slot, obj) =>
|
case AvatarAction.EquipmentInHand(player_guid, slot, obj) =>
|
||||||
AvatarEvents.publish(
|
AvatarEvents.publish(
|
||||||
AvatarServiceResponse("/Avatar/" + forChannel, player_guid, AvatarServiceResponse.EquipmentInHand(slot, obj))
|
AvatarServiceResponse(s"/$forChannel/Avatar", player_guid, AvatarServiceResponse.EquipmentInHand(slot, obj))
|
||||||
)
|
)
|
||||||
case AvatarAction.EquipmentOnGround(player_guid, pos, orient, obj) =>
|
case AvatarAction.EquipmentOnGround(player_guid, pos, orient, obj) =>
|
||||||
AvatarEvents.publish(
|
AvatarEvents.publish(
|
||||||
AvatarServiceResponse("/Avatar/" + forChannel, player_guid, AvatarServiceResponse.EquipmentOnGround(pos, orient, obj))
|
AvatarServiceResponse(s"/$forChannel/Avatar", player_guid, AvatarServiceResponse.EquipmentOnGround(pos, orient, obj))
|
||||||
)
|
)
|
||||||
case AvatarAction.LoadPlayer(player_guid, pdata) =>
|
case AvatarAction.LoadPlayer(player_guid, pdata) =>
|
||||||
AvatarEvents.publish(
|
AvatarEvents.publish(
|
||||||
AvatarServiceResponse("/Avatar/" + forChannel, player_guid, AvatarServiceResponse.LoadPlayer(pdata))
|
AvatarServiceResponse(s"/$forChannel/Avatar", player_guid, AvatarServiceResponse.LoadPlayer(pdata))
|
||||||
)
|
)
|
||||||
case AvatarAction.ObjectDelete(player_guid, item_guid, unk) =>
|
case AvatarAction.ObjectDelete(player_guid, item_guid, unk) =>
|
||||||
AvatarEvents.publish(
|
AvatarEvents.publish(
|
||||||
AvatarServiceResponse("/Avatar/" + forChannel, player_guid, AvatarServiceResponse.ObjectDelete(item_guid, unk))
|
AvatarServiceResponse(s"/$forChannel/Avatar", player_guid, AvatarServiceResponse.ObjectDelete(item_guid, unk))
|
||||||
)
|
)
|
||||||
case AvatarAction.ObjectHeld(player_guid, slot) =>
|
case AvatarAction.ObjectHeld(player_guid, slot) =>
|
||||||
AvatarEvents.publish(
|
AvatarEvents.publish(
|
||||||
AvatarServiceResponse("/Avatar/" + forChannel, player_guid, AvatarServiceResponse.ObjectHeld(slot))
|
AvatarServiceResponse(s"/$forChannel/Avatar", player_guid, AvatarServiceResponse.ObjectHeld(slot))
|
||||||
)
|
)
|
||||||
case AvatarAction.PlanetsideAttribute(guid, attribute_type, attribute_value) =>
|
case AvatarAction.PlanetsideAttribute(guid, attribute_type, attribute_value) =>
|
||||||
AvatarEvents.publish(
|
AvatarEvents.publish(
|
||||||
AvatarServiceResponse("/Avatar/" + forChannel, guid, AvatarServiceResponse.PlanetSideAttribute(attribute_type, attribute_value))
|
AvatarServiceResponse(s"/$forChannel/Avatar", guid, AvatarServiceResponse.PlanetSideAttribute(attribute_type, attribute_value))
|
||||||
)
|
)
|
||||||
case AvatarAction.PlayerState(guid, msg, spectator, weapon) =>
|
case AvatarAction.PlayerState(guid, msg, spectator, weapon) =>
|
||||||
AvatarEvents.publish(
|
AvatarEvents.publish(
|
||||||
AvatarServiceResponse("/Avatar/" + forChannel, guid, AvatarServiceResponse.PlayerState(msg, spectator, weapon))
|
AvatarServiceResponse(s"/$forChannel/Avatar", guid, AvatarServiceResponse.PlayerState(msg, spectator, weapon))
|
||||||
)
|
)
|
||||||
case AvatarAction.Reload(player_guid, mag) =>
|
case AvatarAction.Reload(player_guid, mag) =>
|
||||||
AvatarEvents.publish(
|
AvatarEvents.publish(
|
||||||
AvatarServiceResponse("/Avatar/" + forChannel, player_guid, AvatarServiceResponse.Reload(mag))
|
AvatarServiceResponse(s"/$forChannel/Avatar", player_guid, AvatarServiceResponse.Reload(mag))
|
||||||
)
|
)
|
||||||
case _ => ;
|
case _ => ;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
58
pslogin/src/main/scala/LocalService.scala
Normal file
58
pslogin/src/main/scala/LocalService.scala
Normal file
|
|
@ -0,0 +1,58 @@
|
||||||
|
// Copyright (c) 2017 PSForever
|
||||||
|
import akka.actor.Actor
|
||||||
|
import net.psforever.packet.game.PlanetSideGUID
|
||||||
|
|
||||||
|
object LocalAction {
|
||||||
|
trait Action
|
||||||
|
|
||||||
|
final case class Door(player_guid : PlanetSideGUID) extends Action
|
||||||
|
}
|
||||||
|
|
||||||
|
object LocalServiceResponse {
|
||||||
|
trait Response
|
||||||
|
|
||||||
|
final case class Door(player_guid : PlanetSideGUID) extends Response
|
||||||
|
}
|
||||||
|
|
||||||
|
final case class LocalServiceMessage(forChannel : String, actionMessage : LocalAction.Action)
|
||||||
|
|
||||||
|
final case class LocalServiceResponse(toChannel : String, avatar_guid : PlanetSideGUID, replyMessage : LocalServiceResponse.Response) extends GenericEventBusMsg
|
||||||
|
|
||||||
|
/*
|
||||||
|
/LocalEnvironment/
|
||||||
|
*/
|
||||||
|
|
||||||
|
class LocalService extends Actor {
|
||||||
|
//import LocalService._
|
||||||
|
private [this] val log = org.log4s.getLogger
|
||||||
|
|
||||||
|
override def preStart = {
|
||||||
|
log.info("Starting...")
|
||||||
|
}
|
||||||
|
|
||||||
|
val LocalEvents = new GenericEventBus[LocalServiceResponse]
|
||||||
|
|
||||||
|
def receive = {
|
||||||
|
case Service.Join(channel) =>
|
||||||
|
val path = s"/$channel/LocalEnvironment"
|
||||||
|
val who = sender()
|
||||||
|
log.info(s"$who has joined $path")
|
||||||
|
LocalEvents.subscribe(who, path)
|
||||||
|
case Service.Leave() =>
|
||||||
|
LocalEvents.unsubscribe(sender())
|
||||||
|
case Service.LeaveAll() =>
|
||||||
|
LocalEvents.unsubscribe(sender())
|
||||||
|
|
||||||
|
case LocalServiceMessage(forChannel, action) =>
|
||||||
|
action match {
|
||||||
|
case LocalAction.Door(player_guid) =>
|
||||||
|
LocalEvents.publish(
|
||||||
|
LocalServiceResponse(s"/$forChannel/LocalEnvironment" + forChannel, player_guid, LocalServiceResponse.Door(player_guid))
|
||||||
|
)
|
||||||
|
case _ => ;
|
||||||
|
}
|
||||||
|
|
||||||
|
case msg =>
|
||||||
|
log.info(s"Unhandled message $msg from $sender")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -3,7 +3,7 @@ import java.net.InetAddress
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
|
|
||||||
import akka.actor.{ActorRef, ActorSystem, Props}
|
import akka.actor.{ActorContext, ActorRef, ActorSystem, Props}
|
||||||
import akka.routing.RandomPool
|
import akka.routing.RandomPool
|
||||||
import ch.qos.logback.classic.LoggerContext
|
import ch.qos.logback.classic.LoggerContext
|
||||||
import ch.qos.logback.classic.joran.JoranConfigurator
|
import ch.qos.logback.classic.joran.JoranConfigurator
|
||||||
|
|
@ -202,6 +202,7 @@ object PsLogin {
|
||||||
val serviceManager = ServiceManager.boot
|
val serviceManager = ServiceManager.boot
|
||||||
serviceManager ! ServiceManager.Register(RandomPool(50).props(Props[TaskResolver]), "taskResolver")
|
serviceManager ! ServiceManager.Register(RandomPool(50).props(Props[TaskResolver]), "taskResolver")
|
||||||
serviceManager ! ServiceManager.Register(Props[AvatarService], "avatar")
|
serviceManager ! ServiceManager.Register(Props[AvatarService], "avatar")
|
||||||
|
serviceManager ! ServiceManager.Register(Props[LocalService], "local")
|
||||||
serviceManager ! ServiceManager.Register(Props(classOf[InterstellarCluster], createContinents()), "galaxy")
|
serviceManager ! ServiceManager.Register(Props(classOf[InterstellarCluster], createContinents()), "galaxy")
|
||||||
|
|
||||||
/** Create two actors for handling the login and world server endpoints */
|
/** Create two actors for handling the login and world server endpoints */
|
||||||
|
|
@ -222,20 +223,38 @@ object PsLogin {
|
||||||
def createContinents() : List[Zone] = {
|
def createContinents() : List[Zone] = {
|
||||||
val map13 = new ZoneMap("map13") {
|
val map13 = new ZoneMap("map13") {
|
||||||
import net.psforever.objects.GlobalDefinitions._
|
import net.psforever.objects.GlobalDefinitions._
|
||||||
val ddef = new net.psforever.objects.doors.DoorDefinition(242) {} //generic door
|
|
||||||
|
|
||||||
LocalObject(DoorObjectBuilder(ddef, 330))
|
LocalObject(DoorObjectBuilder(door, 330))
|
||||||
LocalObject(DoorObjectBuilder(ddef, 332))
|
LocalObject(DoorObjectBuilder(door, 332))
|
||||||
LocalObject(DoorObjectBuilder(ddef, 372))
|
LocalObject(DoorObjectBuilder(door, 372))
|
||||||
LocalObject(DoorObjectBuilder(ddef, 373))
|
LocalObject(DoorObjectBuilder(door, 373))
|
||||||
|
LocalObject(IFFLockObjectBuilder(external_lock, 556))
|
||||||
|
LocalObject(IFFLockObjectBuilder(external_lock, 558))
|
||||||
LocalObject(TerminalObjectBuilder(cert_terminal, 186))
|
LocalObject(TerminalObjectBuilder(cert_terminal, 186))
|
||||||
LocalObject(TerminalObjectBuilder(cert_terminal, 187))
|
LocalObject(TerminalObjectBuilder(cert_terminal, 187))
|
||||||
LocalObject(TerminalObjectBuilder(cert_terminal, 188))
|
LocalObject(TerminalObjectBuilder(cert_terminal, 188))
|
||||||
LocalObject(TerminalObjectBuilder(order_terminal, 853))
|
LocalObject(TerminalObjectBuilder(order_terminal, 853))
|
||||||
LocalObject(TerminalObjectBuilder(order_terminal, 855))
|
LocalObject(TerminalObjectBuilder(order_terminal, 855))
|
||||||
LocalObject(TerminalObjectBuilder(order_terminal, 860))
|
LocalObject(TerminalObjectBuilder(order_terminal, 860))
|
||||||
|
|
||||||
|
LocalBases = 30
|
||||||
|
|
||||||
|
ObjectToBase(330, 29)
|
||||||
|
ObjectToBase(332, 29)
|
||||||
|
ObjectToBase(556, 29)
|
||||||
|
ObjectToBase(558, 29)
|
||||||
|
DoorToLock(330, 558)
|
||||||
|
DoorToLock(332, 556)
|
||||||
|
}
|
||||||
|
val home3 = new Zone("home3", map13, 13) {
|
||||||
|
override def Init(implicit context : ActorContext) : Unit = {
|
||||||
|
super.Init(context)
|
||||||
|
|
||||||
|
import net.psforever.types.PlanetSideEmpire
|
||||||
|
Base(2).get.Faction = PlanetSideEmpire.VS //HART building C
|
||||||
|
Base(29).get.Faction = PlanetSideEmpire.NC //South Villa Gun Tower
|
||||||
|
}
|
||||||
}
|
}
|
||||||
val home3 = Zone("home3", map13, 13)
|
|
||||||
|
|
||||||
home3 ::
|
home3 ::
|
||||||
Nil
|
Nil
|
||||||
|
|
|
||||||
29
pslogin/src/main/scala/Service.scala
Normal file
29
pslogin/src/main/scala/Service.scala
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
// Copyright (c) 2017 PSForever
|
||||||
|
import akka.event.{ActorEventBus, SubchannelClassification}
|
||||||
|
import akka.util.Subclassification
|
||||||
|
|
||||||
|
object Service {
|
||||||
|
final case class Join(channel : String)
|
||||||
|
final case class Leave()
|
||||||
|
final case class LeaveAll()
|
||||||
|
}
|
||||||
|
|
||||||
|
trait GenericEventBusMsg {
|
||||||
|
def toChannel : String
|
||||||
|
}
|
||||||
|
|
||||||
|
class GenericEventBus[A <: GenericEventBusMsg] extends ActorEventBus with SubchannelClassification {
|
||||||
|
type Event = A
|
||||||
|
type Classifier = String
|
||||||
|
|
||||||
|
protected def classify(event: Event): Classifier = event.toChannel
|
||||||
|
|
||||||
|
protected def subclassification = new Subclassification[Classifier] {
|
||||||
|
def isEqual(x: Classifier, y: Classifier) = x == y
|
||||||
|
def isSubclass(x: Classifier, y: Classifier) = x.startsWith(y)
|
||||||
|
}
|
||||||
|
|
||||||
|
protected def publish(event: Event, subscriber: Subscriber): Unit = {
|
||||||
|
subscriber ! event
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -11,7 +11,7 @@ import org.log4s.MDC
|
||||||
import MDCContextAware.Implicits._
|
import MDCContextAware.Implicits._
|
||||||
import ServiceManager.Lookup
|
import ServiceManager.Lookup
|
||||||
import net.psforever.objects._
|
import net.psforever.objects._
|
||||||
import net.psforever.objects.doors.Door
|
import net.psforever.objects.doors.{Door, IFFLock}
|
||||||
import net.psforever.objects.zones.{InterstellarCluster, Zone}
|
import net.psforever.objects.zones.{InterstellarCluster, Zone}
|
||||||
import net.psforever.objects.entity.IdentifiableEntity
|
import net.psforever.objects.entity.IdentifiableEntity
|
||||||
import net.psforever.objects.equipment._
|
import net.psforever.objects.equipment._
|
||||||
|
|
@ -32,9 +32,10 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
var sessionId : Long = 0
|
var sessionId : Long = 0
|
||||||
var leftRef : ActorRef = ActorRef.noSender
|
var leftRef : ActorRef = ActorRef.noSender
|
||||||
var rightRef : ActorRef = ActorRef.noSender
|
var rightRef : ActorRef = ActorRef.noSender
|
||||||
var avatarService = Actor.noSender
|
var avatarService : ActorRef = ActorRef.noSender
|
||||||
var taskResolver = Actor.noSender
|
var localService : ActorRef = ActorRef.noSender
|
||||||
var galaxy = Actor.noSender
|
var taskResolver : ActorRef = Actor.noSender
|
||||||
|
var galaxy : ActorRef = Actor.noSender
|
||||||
var continent : Zone = null
|
var continent : Zone = null
|
||||||
|
|
||||||
var clientKeepAlive : Cancellable = WorldSessionActor.DefaultCancellable
|
var clientKeepAlive : Cancellable = WorldSessionActor.DefaultCancellable
|
||||||
|
|
@ -43,7 +44,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
if(clientKeepAlive != null)
|
if(clientKeepAlive != null)
|
||||||
clientKeepAlive.cancel()
|
clientKeepAlive.cancel()
|
||||||
|
|
||||||
avatarService ! Leave()
|
avatarService ! Service.Leave()
|
||||||
LivePlayerList.Remove(sessionId) match {
|
LivePlayerList.Remove(sessionId) match {
|
||||||
case Some(tplayer) =>
|
case Some(tplayer) =>
|
||||||
if(tplayer.HasGUID) {
|
if(tplayer.HasGUID) {
|
||||||
|
|
@ -70,6 +71,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
}
|
}
|
||||||
context.become(Started)
|
context.become(Started)
|
||||||
ServiceManager.serviceManager ! Lookup("avatar")
|
ServiceManager.serviceManager ! Lookup("avatar")
|
||||||
|
ServiceManager.serviceManager ! Lookup("local")
|
||||||
ServiceManager.serviceManager ! Lookup("taskResolver")
|
ServiceManager.serviceManager ! Lookup("taskResolver")
|
||||||
ServiceManager.serviceManager ! Lookup("galaxy")
|
ServiceManager.serviceManager ! Lookup("galaxy")
|
||||||
|
|
||||||
|
|
@ -82,6 +84,9 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
case ServiceManager.LookupResult("avatar", endpoint) =>
|
case ServiceManager.LookupResult("avatar", endpoint) =>
|
||||||
avatarService = endpoint
|
avatarService = endpoint
|
||||||
log.info("ID: " + sessionId + " Got avatar service " + endpoint)
|
log.info("ID: " + sessionId + " Got avatar service " + endpoint)
|
||||||
|
case ServiceManager.LookupResult("local", endpoint) =>
|
||||||
|
localService = endpoint
|
||||||
|
log.info("ID: " + sessionId + " Got local service " + endpoint)
|
||||||
case ServiceManager.LookupResult("taskResolver", endpoint) =>
|
case ServiceManager.LookupResult("taskResolver", endpoint) =>
|
||||||
taskResolver = endpoint
|
taskResolver = endpoint
|
||||||
log.info("ID: " + sessionId + " Got task resolver service " + endpoint)
|
log.info("ID: " + sessionId + " Got task resolver service " + endpoint)
|
||||||
|
|
@ -724,7 +729,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
avatarService ! Join(player.Continent)
|
avatarService ! Service.Join(player.Continent)
|
||||||
self ! SetCurrentAvatar(player)
|
self ! SetCurrentAvatar(player)
|
||||||
|
|
||||||
case msg @ PlayerStateMessageUpstream(avatar_guid, pos, vel, yaw, pitch, yaw_upper, seq_time, unk3, is_crouching, is_jumping, unk4, is_cloaking, unk5, unk6) =>
|
case msg @ PlayerStateMessageUpstream(avatar_guid, pos, vel, yaw, pitch, yaw_upper, seq_time, unk3, is_crouching, is_jumping, unk4, is_cloaking, unk5, unk6) =>
|
||||||
|
|
@ -957,8 +962,23 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
// TODO: Not all incoming UseItemMessage's respond with another UseItemMessage (i.e. doors only send out GenericObjectStateMsg)
|
// TODO: Not all incoming UseItemMessage's respond with another UseItemMessage (i.e. doors only send out GenericObjectStateMsg)
|
||||||
continent.GUID(object_guid) match {
|
continent.GUID(object_guid) match {
|
||||||
case Some(door : Door) =>
|
case Some(door : Door) =>
|
||||||
log.info("Door action!")
|
continent.Map.DoorToLock.get(object_guid.guid) match { //check for IFFLock
|
||||||
door.Actor ! Door.Request(player, msg)
|
case Some(lock_guid) =>
|
||||||
|
val lock_hacked = continent.GUID(lock_guid).get.asInstanceOf[IFFLock].Hacker.contains(player.Faction)
|
||||||
|
continent.Map.ObjectToBase.get(lock_guid) match { //check for associated base
|
||||||
|
case Some(base_id) =>
|
||||||
|
if(continent.Base(base_id).get.Faction == player.Faction || lock_hacked) { //either base allegiance aligns or lock is hacked
|
||||||
|
door.Actor ! Door.Use(player, msg)
|
||||||
|
}
|
||||||
|
case None =>
|
||||||
|
if(lock_hacked) { //is lock hacked?
|
||||||
|
door.Actor ! Door.Use(player, msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case None =>
|
||||||
|
door.Actor ! Door.Use(player, msg) //let door open freely
|
||||||
|
}
|
||||||
|
|
||||||
case Some(obj : PlanetSideGameObject) =>
|
case Some(obj : PlanetSideGameObject) =>
|
||||||
if(itemType != 121) {
|
if(itemType != 121) {
|
||||||
sendResponse(PacketCoding.CreateGamePacket(0, UseItemMessage(avatar_guid, unk1, object_guid, unk2, unk3, unk4, unk5, unk6, unk7, unk8, itemType)))
|
sendResponse(PacketCoding.CreateGamePacket(0, UseItemMessage(avatar_guid, unk1, object_guid, unk2, unk3, unk4, unk5, unk6, unk7, unk8, itemType)))
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue