Initial merge of some PTS v3 changes (#281)

This commit is contained in:
Mazo 2019-10-22 17:15:46 +01:00 committed by pschord
parent 02ab92e537
commit 3e40a2f319
27 changed files with 893 additions and 84 deletions

View file

@ -463,6 +463,12 @@ object GlobalDefinitions {
val flamethrower_ammo = AmmoBoxDefinition(Ammo.flamethrower_ammo)
val winchester_ammo = AmmoBoxDefinition(Ammo.winchester_ammo)
val pellet_gun_ammo = AmmoBoxDefinition(Ammo.pellet_gun_ammo)
val six_shooter_ammo = AmmoBoxDefinition(Ammo.six_shooter_ammo)
val dualcycler_ammo = AmmoBoxDefinition(Ammo.dualcycler_ammo)
val pounder_ammo = AmmoBoxDefinition(Ammo.pounder_ammo)
@ -652,6 +658,14 @@ object GlobalDefinitions {
val flamethrower = ToolDefinition(ObjectClass.flamethrower)
val winchester = ToolDefinition(ObjectClass.winchester)
val pellet_gun = ToolDefinition(ObjectClass.pellet_gun)
val six_shooter = ToolDefinition(ObjectClass.six_shooter)
val dynomite = ToolDefinition(ObjectClass.dynomite)
val trhev_dualcycler = new ToolDefinition(ObjectClass.trhev_dualcycler) {
override def NextFireModeIndex(index : Int) : Int = index
}
@ -1204,6 +1218,21 @@ object GlobalDefinitions {
case PlanetSideEmpire.NEUTRAL => bullet_9mm
}
}
/**
* For a given faction, provide the AP ammunition for the medium assault rifle.
* The ammunition value here must work with the result of obtaining the rifle using the faction.
* @param faction the faction
* @return thr `AmmoBoxDefinition` for the rifle's ammo
* @see `GlobalDefinitions.MediumRifle`
*/
def MediumRifleAPAmmo(faction : PlanetSideEmpire.Value) : AmmoBoxDefinition = {
faction match {
case PlanetSideEmpire.TR => bullet_9mm_AP
case PlanetSideEmpire.NC => bullet_9mm_AP
case PlanetSideEmpire.VS => energy_cell
case PlanetSideEmpire.NEUTRAL => bullet_9mm_AP
}
}
/**
* For a given faction, provide the heavy assault rifle.
@ -1236,6 +1265,22 @@ object GlobalDefinitions {
}
}
/**
* For a given faction, provide the AP ammunition for the heavy assault rifle.
* The ammunition value here must work with the result of obtaining the rifle using the faction.
* @param faction the faction
* @return thr `AmmoBoxDefinition` for the rifle's ammo
* @see `GlobalDefinitions.HeavyRifle`
*/
def HeavyRifleAPAmmo(faction : PlanetSideEmpire.Value) : AmmoBoxDefinition = {
faction match {
case PlanetSideEmpire.TR => bullet_9mm_AP
case PlanetSideEmpire.NC => shotgun_shell_AP
case PlanetSideEmpire.VS => energy_cell
case PlanetSideEmpire.NEUTRAL => bullet_9mm_AP
}
}
/**
* For a given faction, provide the anti-vehicular launcher.
* @param faction the faction
@ -1268,13 +1313,13 @@ object GlobalDefinitions {
def MAXArms(subtype : Int, faction : PlanetSideEmpire.Value) : ToolDefinition = {
if(subtype == 1) {
AIMAX(faction)
AI_MAX(faction)
}
else if(subtype == 2) {
AVMAX(faction)
AV_MAX(faction)
}
else if(subtype == 3) {
AAMAX(faction)
AA_MAX(faction)
}
else {
suppressor //there are no common pool MAX arms
@ -1292,7 +1337,7 @@ object GlobalDefinitions {
}
}
def AIMAX(faction : PlanetSideEmpire.Value) : ToolDefinition = {
def AI_MAX(faction : PlanetSideEmpire.Value) : ToolDefinition = {
faction match {
case PlanetSideEmpire.TR => trhev_dualcycler
case PlanetSideEmpire.NC => nchev_scattercannon
@ -1301,7 +1346,16 @@ object GlobalDefinitions {
}
}
def AVMAX(faction : PlanetSideEmpire.Value) : ToolDefinition = {
def AI_MAXAmmo(faction : PlanetSideEmpire.Value) : AmmoBoxDefinition = {
faction match {
case PlanetSideEmpire.TR => dualcycler_ammo
case PlanetSideEmpire.NC => scattercannon_ammo
case PlanetSideEmpire.VS => quasar_ammo
case PlanetSideEmpire.NEUTRAL => bullet_9mm //there are no common pool MAX arms
}
}
def AV_MAX(faction : PlanetSideEmpire.Value) : ToolDefinition = {
faction match {
case PlanetSideEmpire.TR => trhev_pounder
case PlanetSideEmpire.NC => nchev_falcon
@ -1310,7 +1364,16 @@ object GlobalDefinitions {
}
}
def AAMAX(faction : PlanetSideEmpire.Value) : ToolDefinition = {
def AV_MAXAmmo(faction : PlanetSideEmpire.Value) : AmmoBoxDefinition = {
faction match {
case PlanetSideEmpire.TR => pounder_ammo
case PlanetSideEmpire.NC => falcon_ammo
case PlanetSideEmpire.VS => comet_ammo
case PlanetSideEmpire.NEUTRAL => bullet_9mm //there are no common pool MAX arms
}
}
def AA_MAX(faction : PlanetSideEmpire.Value) : ToolDefinition = {
faction match {
case PlanetSideEmpire.TR => trhev_burster
case PlanetSideEmpire.NC => nchev_sparrow
@ -1319,6 +1382,15 @@ object GlobalDefinitions {
}
}
def AA_MAXAmmo(faction : PlanetSideEmpire.Value) : AmmoBoxDefinition = {
faction match {
case PlanetSideEmpire.TR => burster_ammo
case PlanetSideEmpire.NC => sparrow_ammo
case PlanetSideEmpire.VS => starfire_ammo
case PlanetSideEmpire.NEUTRAL => bullet_9mm //there are no common pool MAX arms
}
}
def PortableMannedTurret(faction :PlanetSideEmpire.Value) : TurretDeployableDefinition = {
faction match {
case PlanetSideEmpire.TR => portable_manned_turret_tr
@ -1336,7 +1408,7 @@ object GlobalDefinitions {
*/
def isGrenade(edef : EquipmentDefinition) : Boolean = {
edef match {
case `frag_grenade` | `jammer_grenade` | `plasma_grenade` =>
case `frag_grenade` | `jammer_grenade` | `plasma_grenade` | `dynomite` =>
true
case _ =>
false
@ -1651,6 +1723,18 @@ object GlobalDefinitions {
flamethrower_ammo.Capacity = 100
flamethrower_ammo.Tile = InventoryTile.Tile44
winchester_ammo.Name = "winchester_ammo"
winchester_ammo.Capacity = 10
winchester_ammo.Tile = InventoryTile.Tile33
pellet_gun_ammo.Name = "pellet_gun_ammo"
pellet_gun_ammo.Capacity = 8
pellet_gun_ammo.Tile = InventoryTile.Tile33
six_shooter_ammo.Name = "six_shooter_ammo"
six_shooter_ammo.Capacity = 12
six_shooter_ammo.Tile = InventoryTile.Tile33
dualcycler_ammo.Name = "dualcycler_ammo"
dualcycler_ammo.Capacity = 100
dualcycler_ammo.Tile = InventoryTile.Tile44
@ -4079,6 +4163,47 @@ object GlobalDefinitions {
flamethrower.FireModes(1).Rounds = 50
flamethrower.Tile = InventoryTile.Tile63
winchester.Name = "winchester"
winchester.Size = EquipmentSize.Rifle
winchester.AmmoTypes += winchester_ammo
winchester.ProjectileTypes += winchester_projectile
winchester.FireModes += new FireModeDefinition
winchester.FireModes.head.AmmoTypeIndices += 0
winchester.FireModes.head.AmmoSlotIndex = 0
winchester.FireModes.head.Magazine = 1
winchester.Tile = InventoryTile.Tile93
pellet_gun.Name = "pellet_gun"
pellet_gun.Size = EquipmentSize.Rifle
pellet_gun.AmmoTypes += pellet_gun_ammo
pellet_gun.ProjectileTypes += pellet_gun_projectile
pellet_gun.FireModes += new PelletFireModeDefinition
pellet_gun.FireModes.head.AmmoTypeIndices += 0
pellet_gun.FireModes.head.AmmoSlotIndex = 0
pellet_gun.FireModes.head.Magazine = 1
pellet_gun.FireModes.head.Chamber = 8 //1 shells * 8 pellets = 8
pellet_gun.Tile = InventoryTile.Tile63
six_shooter.Name = "six_shooter"
six_shooter.Size = EquipmentSize.Pistol
six_shooter.AmmoTypes += six_shooter_ammo
six_shooter.ProjectileTypes += six_shooter_projectile
six_shooter.FireModes += new FireModeDefinition
six_shooter.FireModes.head.AmmoTypeIndices += 0
six_shooter.FireModes.head.AmmoSlotIndex = 0
six_shooter.FireModes.head.Magazine = 6
six_shooter.Tile = InventoryTile.Tile33
dynomite.Name = "dynomite"
dynomite.Size = EquipmentSize.Pistol
dynomite.AmmoTypes += frag_grenade_ammo
dynomite.ProjectileTypes += dynomite_projectile
dynomite.FireModes += new FireModeDefinition
dynomite.FireModes.head.AmmoTypeIndices += 0
dynomite.FireModes.head.AmmoSlotIndex = 0
dynomite.FireModes.head.Magazine = 1
dynomite.Tile = InventoryTile.Tile22
trhev_dualcycler.Name = "trhev_dualcycler"
trhev_dualcycler.Size = EquipmentSize.Max
trhev_dualcycler.AmmoTypes += dualcycler_ammo

View file

@ -48,9 +48,14 @@ class Player(private val core : Avatar) extends PlanetSideGameObject
private var continent : String = "home2" //the zone id
//SouNourS things
/** Last medkituse. */
var lastMedkit : Long = 0
var silenced : Boolean = false
var firstLoad : Boolean = false
def FirstLoad : Boolean = firstLoad
def FirstLoad_=(status : Boolean) : Boolean = {
firstLoad = status
FirstLoad
}
var death_by : Int = 0
var lastSeenStreamMessage : Array[Long] = Array.fill[Long](65535)(0L)
var lastShotSeq_time : Int = -1
/** From PlanetsideAttributeMessage */

View file

@ -7,6 +7,7 @@ import net.psforever.objects.vital.resistance.ResistanceProfile
import net.psforever.types.{ExoSuitType, PlanetSideEmpire, Vector3}
final case class PlayerSource(name : String,
char_id : Long,
obj_def : ObjectDefinition,
faction : PlanetSideEmpire.Value,
exosuit : ExoSuitType.Value,
@ -19,6 +20,7 @@ final case class PlayerSource(name : String,
modifiers : ResistanceProfile) extends SourceEntry {
override def Name = name
override def Faction = faction
override def CharId = char_id
def Definition = obj_def
def ExoSuit = exosuit
def Seated = seated
@ -32,7 +34,7 @@ final case class PlayerSource(name : String,
object PlayerSource {
def apply(tplayer : Player) : PlayerSource = {
PlayerSource(tplayer.Name, tplayer.Definition, tplayer.Faction, tplayer.ExoSuit, tplayer.VehicleSeated.nonEmpty,
PlayerSource(tplayer.Name, tplayer.CharId, tplayer.Definition, tplayer.Faction, tplayer.ExoSuit, tplayer.VehicleSeated.nonEmpty,
tplayer.Health, tplayer.Armor, tplayer.Position, tplayer.Orientation, tplayer.Velocity, tplayer.asInstanceOf[ResistanceProfile])
}
}

View file

@ -155,6 +155,7 @@ object Building {
def Structure(buildingType : StructureType.Value, location : Vector3)(guid : Int, map_id : Int, zone : Zone, context : ActorContext) : Building = {
import akka.actor.Props
val obj = new Building(guid, map_id, zone, buildingType, GlobalDefinitions.building)
obj.Position = location
obj.Actor = context.actorOf(Props(classOf[BuildingControl], obj), s"$map_id-$buildingType-building")

View file

@ -66,7 +66,10 @@ object EquipmentTerminalDefinition {
"lancer_cartridge" -> MakeAmmoBox(lancer_cartridge),
"bolt" -> MakeAmmoBox(bolt),
"oicw_ammo" -> MakeAmmoBox(oicw_ammo), //scorpion missile
"flamethrower_ammo" -> MakeAmmoBox(flamethrower_ammo)
"flamethrower_ammo" -> MakeAmmoBox(flamethrower_ammo),
"winchester_ammo" -> MakeAmmoBox(winchester_ammo),
"pellet_gun_ammo" -> MakeAmmoBox(pellet_gun_ammo),
"six_shooter_ammo" -> MakeAmmoBox(six_shooter_ammo)
)
val maxAmmo : Map[String, () => Equipment] = Map(
"dualcycler_ammo" -> MakeAmmoBox(dualcycler_ammo),
@ -172,7 +175,11 @@ object EquipmentTerminalDefinition {
"heavy_sniper" -> MakeTool(heavy_sniper), //hsr
"bolt_driver" -> MakeTool(bolt_driver),
"oicw" -> MakeTool(oicw), //scorpion
"flamethrower" -> MakeTool(flamethrower)
"flamethrower" -> MakeTool(flamethrower),
"winchester" -> MakeTool(winchester),
"pellet_gun" -> MakeTool(pellet_gun),
"six_shooter" -> MakeTool(six_shooter),
"dynomite" -> MakeTool(dynomite)
)
/**
* A `Map` of operations for producing the `Tool` `Equipment` for utilities.

View file

@ -26,6 +26,8 @@ final case class HealFromImplant(target : PlayerSource, amount : Int, implant :
final case class HealFromExoSuitChange(target : PlayerSource, exosuit : ExoSuitType.Value) extends HealingActivity(target)
final case class RepairFromKit(target : PlayerSource, amount : Int, kit_def : KitDefinition) extends HealingActivity(target)
final case class RepairFromTerm(target : VehicleSource, amount : Int, term_def : TerminalDefinition) extends HealingActivity(target)
final case class VehicleShieldCharge(target : VehicleSource, amount : Int) extends HealingActivity(target) //TODO facility

View file

@ -44,6 +44,7 @@ object LoginRespMessage extends Marshallable[LoginRespMessage] {
object LoginError extends Enumeration {
type Type = Value
val Success = Value(0)
val unk1 = Value(1)
val BadUsernameOrPassword = Value(5)
val BadVersion = Value(0xf)
@ -53,18 +54,19 @@ object LoginRespMessage extends Marshallable[LoginRespMessage] {
object StationError extends Enumeration {
type Type = Value
val AccountActive = Value(1)
val AccountClosed = Value(2)
val AccountClosed = Value(2) // "Your Station account is currently closed"
implicit val codec = PacketHelpers.createLongEnumerationCodec(this, uint32L)
}
object StationSubscriptionStatus extends Enumeration {
type Type = Value
val None = Value(1)
val Active = Value(2) /// Not sure about this one (guessing)
val Closed = Value(4)
val Trial = Value(5) /// Not sure about this one either
val TrialExpired = Value(6)
val None = Value(1) // "You do not have a PlanetSide subscription"
val Active = Value(2) /// Not sure about this one (guessing) (no ingame error message)
val unk3 = Value(3)
val Closed = Value(4) // "Your PlanetSide subscription is currently closed"
val Trial = Value(5) /// Not sure about this one either (no ingame error message)
val TrialExpired = Value(6) // "Your trial PlanetSide subscription has expired"
implicit val codec = PacketHelpers.createLongEnumerationCodec(this, uint32L)
}

View file

@ -126,11 +126,12 @@ import scodec.codecs._
* - OLD: "Info under avatar name : 0 = Looking For Squad Members, 1 = LFS`"<br>
* `35 - BR. Value is the BR`<br>
* `36 - CR. Value is the CR`<br>
* `38 - Spawn active or not. MUST use base MapId not base GUID`<br>
* `43 - Info on avatar name : 0 = Nothing, 1 = "(LD)" message`<br>
* `45 - NTU charge bar 0-10, 5 = 50% full. Seems to apply to both ANT and NTU Silo (possibly siphons?)`<br>
* `46 - Sends "Generator damage is at a critical level!" message`
* `47 - Sets base NTU level to CRITICAL. MUST use base modelId not base GUID`<br>
* `48 - Set to 1 to send base power loss message & turns on red warning lights throughout base. MUST use base modelId not base GUID`<br>
* `47 - Sets base NTU level to CRITICAL. MUST use base MapId not base GUID`<br>
* `48 - Set to 1 to send base power loss message & turns on red warning lights throughout base. MUST use base MapId not base GUID`<br>
* `49 - Vehicle texture effects state? (>0 turns on ANT panel glow or ntu silo panel glow + orbs) (bit?)`<br>
* `52 - Vehicle particle effects? (>0 turns on orbs going towards ANT. Doesn't affect silo) (bit?)`<br>
* `53 - LFS. Value is 1 to flag LFS`<br>
@ -143,7 +144,7 @@ import scodec.codecs._
* -- e.g., 13 = 8 + 4 + 1 = fire and LLU and plasma<br>
* `55 - "Someone is attempting to Heal you". Value is 1`<br>
* `56 - "Someone is attempting to Repair you". Value is 1`<br>
* `67 - Enables base shields (from cavern module/lock). MUST use base modelId not GUID`<br>
* `67 - Enables base shields (from cavern module/lock). MUST use base MapId not GUID`<br>
* `73 - "You are locked into the Core Beam. Charging your Module now.". Value is 1 to active`<br>
* `77 - Cavern Facility Captures. Value is the number of captures`<br>
* `78 - Cavern Kills. Value is the number of kills`<br>

View file

@ -18,7 +18,7 @@ object WorldStatus extends Enumeration {
// this enumeration starts from one and is subtracted from before processing (0x005FF12A)
object ServerType extends Enumeration(1) {
type Type = Value
val Development, Beta, Released = Value
val Development, Beta, Released, Released_Gemini = Value
implicit val codec = PacketHelpers.createEnumerationCodec(this, uint8L)
}

View file

@ -392,6 +392,8 @@ object ObjectClass {
final val order_terminal = 612
final val order_terminala = 613
final val order_terminalb = 614
final val portable_ammo_terminal = 684
final val portable_order_terminal = 690
final val targeting_laser_dispenser = 851
final val teleportpad_terminal = 853

View file

@ -8,7 +8,13 @@ object BailType extends Enumeration {
type Type = Value
val Normal = Value(0)
val Unk1 = Value(1) // to have Xtoolspar working
val Unk2 = Value(2) // to have Xtoolspar working
val Unk3 = Value(3) // to have Xtoolspar working
val Kicked = Value(4) // User was kicked out by vehicle owner or locked from vehicle
val Unk5 = Value(5) // to have Xtoolspar working
val Unk6 = Value(6) // to have Xtoolspar working
val Unk7 = Value(7) // to have Xtoolspar working
val Bailed = Value(8) // User bailed out
implicit val codec = PacketHelpers.createEnumerationCodec(this, uint4L)

View file

@ -9,6 +9,7 @@ object CargoStatus extends Enumeration {
val Empty = Value(0)
val InProgress = Value(1)
val UNK1 = Value(2) // to have Xtoolspar working
val Occupied = Value(3)
implicit val codec = PacketHelpers.createEnumerationCodec(this, uint4L)

View file

@ -15,6 +15,9 @@ object DriveState extends Enumeration {
val Undeploying = Value(1)
val Deploying = Value(2)
val Deployed = Value(3)
val UNK4 = Value(4) // to have Xtoolspar working
val UNK5 = Value(5) // to have Xtoolspar working
val UNK6 = Value(6) // to have Xtoolspar working
val State7 = Value(7) //unknown; not encountered on a vehicle that can deploy; functions like Mobile
val State127 = Value(127) //unknown
}

View file

@ -507,6 +507,9 @@ object MeritCommendation extends Enumeration {
if(n > Int.MaxValue) {
Attempt.failure(Err(s"value $n is too high, above maximum integer value ${Int.MaxValue}"))
}
else if(n > 429) { // TODO remove that. It's for use Xtoolspar.
Attempt.failure(Err(s"value $n should not exist"))
}
else {
Attempt.successful(MeritCommendation(n.toInt))
}

View file

@ -36,6 +36,7 @@ object AvatarAction {
final case class ObjectDelete(player_guid : PlanetSideGUID, item_guid : PlanetSideGUID, unk : Int = 0) extends Action
final case class ObjectHeld(player_guid : PlanetSideGUID, slot : Int) extends Action
final case class PlanetsideAttribute(player_guid : PlanetSideGUID, attribute_type : Int, attribute_value : Long) extends Action
final case class PlanetsideAttributeSelf(player_guid : PlanetSideGUID, attribute_type : Int, attribute_value : Long) extends Action
final case class PlayerState(player_guid : PlanetSideGUID, msg : PlayerStateMessageUpstream, spectator : Boolean, weaponInHand : Boolean) extends Action
final case class PickupItem(player_guid : PlanetSideGUID, zone : Zone, target : PlanetSideGameObject with Container, slot : Int, item : Equipment, unk : Int = 0) extends Action
final case class PutDownFDU(player_guid : PlanetSideGUID) extends Action

View file

@ -30,6 +30,7 @@ object AvatarResponse {
final case class ObjectDelete(item_guid : PlanetSideGUID, unk : Int) extends Response
final case class ObjectHeld(slot : Int) extends Response
final case class PlanetsideAttribute(attribute_type : Int, attribute_value : Long) extends Response
final case class PlanetsideAttributeSelf(attribute_type : Int, attribute_value : Long) extends Response
final case class PlayerState(msg : PlayerStateMessageUpstream, spectator : Boolean, weaponInHand : Boolean) extends Response
final case class PutDownFDU(target_guid : PlanetSideGUID) extends Response
final case class Release(player : Player) extends Response

View file

@ -139,6 +139,10 @@ class AvatarService extends Actor {
AvatarEvents.publish(
AvatarServiceResponse(s"/$forChannel/Avatar", guid, AvatarResponse.PlanetsideAttribute(attribute_type, attribute_value))
)
case AvatarAction.PlanetsideAttributeSelf(guid, attribute_type, attribute_value) =>
AvatarEvents.publish(
AvatarServiceResponse(s"/$forChannel/Avatar", guid, AvatarResponse.PlanetsideAttributeSelf(attribute_type, attribute_value))
)
case AvatarAction.PlayerState(guid, msg, spectator, weapon) =>
AvatarEvents.publish(
AvatarServiceResponse(s"/$forChannel/Avatar", guid, AvatarResponse.PlayerState(msg, spectator, weapon))

View file

@ -0,0 +1,18 @@
// Copyright (c) 2017 PSForever
package services.chat
import net.psforever.objects.zones.Zone
import net.psforever.packet.game.{ChatMsg, PlanetSideGUID}
import net.psforever.types.{PlanetSideEmpire, Vector3}
object ChatAction {
sealed trait Action
final case class Local(player_guid : PlanetSideGUID, player_name : String, continent : Zone, player_pos : Vector3, player_faction : PlanetSideEmpire.Value, msg : ChatMsg) extends Action
final case class Tell(player_guid : PlanetSideGUID, player_name : String, msg : ChatMsg) extends Action
final case class Broadcast(player_guid : PlanetSideGUID, player_name : String, continent : Zone, player_pos : Vector3, player_faction : PlanetSideEmpire.Value, msg : ChatMsg) extends Action
final case class Voice(player_guid : PlanetSideGUID, player_name : String, continent : Zone, player_pos : Vector3, player_faction : PlanetSideEmpire.Value, msg : ChatMsg) extends Action
final case class Note(player_guid : PlanetSideGUID, player_name : String, msg : ChatMsg) extends Action
final case class Squad(player_guid : PlanetSideGUID, player_name : String, continent : Zone, player_pos : Vector3, player_faction : PlanetSideEmpire.Value, msg : ChatMsg) extends Action
final case class GM(player_guid : PlanetSideGUID, player_name : String, msg : ChatMsg) extends Action
}

View file

@ -0,0 +1,19 @@
// Copyright (c) 2017 PSForever
package services.chat
import net.psforever.packet.game.PlanetSideGUID
import net.psforever.types.ChatMessageType
object ChatResponse {
sealed trait Response
final case class Local(sender : String, messageType : ChatMessageType.Value, wideContents : Boolean, recipient : String, contents : String, note : Option[String]) extends Response
final case class Tell(sender : String, messageType : ChatMessageType.Value, wideContents : Boolean, recipient : String, contents : String, note : Option[String]) extends Response
final case class UTell(sender : String, messageType : ChatMessageType.Value, wideContents : Boolean, recipient : String, contents : String, note : Option[String]) extends Response
final case class Broadcast(messageType : ChatMessageType.Value, wideContents : Boolean, recipient : String, contents : String, note : Option[String]) extends Response
final case class Voice(messageType : ChatMessageType.Value, wideContents : Boolean, recipient : String, contents : String, note : Option[String]) extends Response
final case class Unk45(sender : String, messageType : ChatMessageType.Value, wideContents : Boolean, recipient : String, contents : String, note : Option[String]) extends Response
final case class Squad(sender : String, messageType : ChatMessageType.Value, wideContents : Boolean, recipient : String, contents : String, note : Option[String]) extends Response
final case class Text(toChannel : String, avatar_guid : PlanetSideGUID, personal : Int, messageType : ChatMessageType.Value, wideContents : Boolean, recipient : String, contents : String, note : Option[String])
}

View file

@ -0,0 +1,113 @@
// Copyright (c) 2017 PSForever
package services.chat
import akka.actor.Actor
import net.psforever.objects.LivePlayerList
import net.psforever.packet.game.{ChatMsg, PlanetSideGUID}
import net.psforever.types.ChatMessageType
import services.{GenericEventBus, Service}
class ChatService extends Actor {
private [this] val log = org.log4s.getLogger
override def preStart = {
log.info("Starting....")
}
val ChatEvents = new GenericEventBus[ChatServiceResponse]
def receive = {
case Service.Join(channel) =>
val path = s"/Chat/$channel"
val who = sender()
log.info(s"$who has joined $path")
ChatEvents.subscribe(who, path)
case Service.Leave(None) =>
ChatEvents.unsubscribe(sender())
case Service.Leave(Some(channel)) =>
val path = s"/Chat/$channel"
val who = sender()
log.info(s"$who has left $path")
ChatEvents.unsubscribe(who, path)
case Service.LeaveAll() =>
ChatEvents.unsubscribe(sender())
case ChatServiceMessage(forChannel, action) =>
action match {
case ChatAction.Local(player_guid, player_name, cont, player_pos, player_faction, msg) => // local
ChatEvents.publish(
ChatServiceResponse(s"/Chat/$forChannel", player_guid, player_name, cont, player_pos, player_faction, 2, ChatMsg(ChatMessageType.CMT_OPEN,msg.wideContents,player_name,msg.contents,None))
)
case ChatAction.Tell(player_guid, player_name, msg) => // tell
var good : Boolean = false
LivePlayerList.WorldPopulation(_ => true).foreach(char => {
if (char.name.equalsIgnoreCase(msg.recipient)) {
good = true
}
})
if(good) {
ChatEvents.publish(
ChatServiceResponse(s"/Chat/$forChannel", player_guid, player_name, target = 0, replyMessage = ChatMsg(ChatMessageType.CMT_TELL,msg.wideContents,msg.recipient,msg.contents,None))
)
ChatEvents.publish(
ChatServiceResponse(s"/Chat/$forChannel", player_guid, player_name, target = 1, replyMessage = ChatMsg(ChatMessageType.U_CMT_TELLFROM,msg.wideContents,msg.recipient,msg.contents,None))
)
} else {
ChatEvents.publish(
ChatServiceResponse(s"/Chat/$forChannel", player_guid, player_name, target = 1, replyMessage = ChatMsg(ChatMessageType.U_CMT_TELLFROM,msg.wideContents,msg.recipient,msg.contents,None))
)
ChatEvents.publish(
ChatServiceResponse(s"/Chat/$forChannel", player_guid, player_name, target = 1, replyMessage = ChatMsg(ChatMessageType.UNK_45,msg.wideContents,"","@NoTell_Target",None))
)
}
case ChatAction.Broadcast(player_guid, player_name, cont, player_pos, player_faction, msg) => // broadcast
ChatEvents.publish(
ChatServiceResponse(s"/Chat/$forChannel", player_guid, player_name, cont, player_pos, player_faction, 2, ChatMsg(msg.messageType,msg.wideContents,player_name,msg.contents,None))
)
case ChatAction.Voice(player_guid, player_name, cont, player_pos, player_faction, msg) => // voice
ChatEvents.publish(
ChatServiceResponse(s"/Chat/$forChannel", player_guid, player_name, cont, player_pos, player_faction, 2, ChatMsg(ChatMessageType.CMT_VOICE,false,player_name,msg.contents,None))
)
case ChatAction.Note(player_guid, player_name, msg) => // note
ChatEvents.publish(
ChatServiceResponse(s"/Chat/$forChannel", player_guid, player_name, target = 1, replyMessage = ChatMsg(ChatMessageType.U_CMT_GMTELLFROM,true, msg.recipient,msg.contents,None))
)
ChatEvents.publish(
ChatServiceResponse(s"/Chat/$forChannel", player_guid, player_name, target = 1, replyMessage = ChatMsg(ChatMessageType.CMT_GMTELL,true,"Server","Why do you try to /note ? That's a GM command ! ... Or not, nobody can /note",None))
)
case ChatAction.Squad(player_guid, player_name, cont, player_pos, player_faction, msg) => // squad
ChatEvents.publish(
ChatServiceResponse(s"/Chat/$forChannel", player_guid, player_name, cont, player_pos, player_faction, 2, ChatMsg(ChatMessageType.CMT_SQUAD,msg.wideContents,player_name,msg.contents,None))
)
case ChatAction.GM(player_guid, player_name, msg) => // GM
msg.messageType match {
case ChatMessageType.CMT_SILENCE =>
ChatEvents.publish(
ChatServiceResponse(s"/Chat/$forChannel", player_guid, msg.contents, target = 0, replyMessage = ChatMsg(ChatMessageType.CMT_SILENCE, true, "", "", None))
)
// if(player_guid != PlanetSideGUID(0)) {
//
// val args = msg.contents.split(" ")
// var silence_name : String = ""
// var silence_time : Int = 5
// if (args.length == 1) {
// silence_name = args(0)
// }
// else if (args.length == 2) {
// silence_name = args(0)
// silence_time = args(1).toInt
// }
// ChatEvents.publish(
// ChatServiceResponse(s"/Chat/$forChannel", player_guid, player_name, target = 1, replyMessage = ChatMsg(ChatMessageType.UNK_45, true, "", silence_name + " silenced for " + silence_time + " min(s)", None))
// )
// }
case _ => ;
}
case _ => ;
}
case msg =>
log.info(s"Unhandled message $msg from $sender")
}
}

View file

@ -0,0 +1,4 @@
// Copyright (c) 2017 PSForever
package services.chat
final case class ChatServiceMessage(forChannel : String, actionMessage : ChatAction.Action)

View file

@ -0,0 +1,18 @@
// Copyright (c) 2017 PSForever
package services.chat
import net.psforever.objects.zones.Zone
import net.psforever.packet.game.{ChatMsg, PlanetSideGUID}
import net.psforever.types.{PlanetSideEmpire, Vector3}
import services.GenericEventBusMsg
final case class ChatServiceResponse(toChannel : String,
avatar_guid : PlanetSideGUID,
avatar_name : String,
cont : Zone = Zone.Nowhere,
avatar_pos : Vector3 = Vector3(0f,0f,0f),
avatar_faction : PlanetSideEmpire.Value = PlanetSideEmpire.NEUTRAL,
target : Int,
replyMessage : ChatMsg
) extends GenericEventBusMsg