Merge pull request #192 from Fate-JH/ams-spawn

AMS Efforts (misc)
This commit is contained in:
Fate-JH 2018-03-05 20:15:11 -05:00 committed by GitHub
commit 71173c171b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
21 changed files with 606 additions and 63 deletions

View file

@ -12,6 +12,7 @@ import net.psforever.objects.serverobject.locks.IFFLockDefinition
import net.psforever.objects.serverobject.mblocker.LockerDefinition
import net.psforever.objects.serverobject.pad.VehicleSpawnPadDefinition
import net.psforever.objects.serverobject.terminals._
import net.psforever.objects.serverobject.tube.SpawnTubeDefinition
import net.psforever.objects.vehicles.{SeatArmorRestriction, UtilityType}
import net.psforever.types.PlanetSideEmpire
@ -486,6 +487,10 @@ object GlobalDefinitions {
*/
val order_terminal = new OrderTerminalDefinition
val ams_respawn_tube = new SpawnTubeDefinition(49) { Name = "ams_respawn_tube" }
val matrix_terminalc = new MatrixTerminalDefinition(519)
val order_terminala = new OrderTerminalABDefinition(613)
val order_terminalb = new OrderTerminalABDefinition(614)
@ -2347,6 +2352,8 @@ object GlobalDefinitions {
ams.Seats(0).ArmorRestriction = SeatArmorRestriction.NoReinforcedOrMax
ams.MountPoints += 1 -> 0
ams.MountPoints += 2 -> 0
ams.Utilities += 1 -> UtilityType.matrix_terminalc
ams.Utilities += 2 -> UtilityType.ams_respawn_tube
ams.Utilities += 3 -> UtilityType.order_terminala
ams.Utilities += 4 -> UtilityType.order_terminalb
ams.Deployment = true

View file

@ -0,0 +1,11 @@
// Copyright (c) 2017 PSForever
package net.psforever.objects.definition.converter
import net.psforever.objects.serverobject.tube.SpawnTube
import net.psforever.packet.game.objectcreate.CommonTerminalData
import scala.util.{Success, Try}
class SpawnTubeConverter extends ObjectCreateConverter[SpawnTube]() {
override def ConstructorData(obj : SpawnTube) : Try[CommonTerminalData] = { Success(CommonTerminalData(obj.Faction)) }
}

View file

@ -0,0 +1,42 @@
// Copyright (c) 2017 PSForever
package net.psforever.objects.serverobject.terminals
import akka.actor.ActorContext
import net.psforever.objects.Player
import net.psforever.objects.serverobject.structures.Amenity
import net.psforever.packet.game.ItemTransactionMessage
/**
* The definition for any `Terminal` that is of a type "matrix_terminal".
*/
class MatrixTerminalDefinition(object_id : Int) extends TerminalDefinition(object_id) {
Name = if(object_id == 517) {
"matrix_terminala"
}
else if(object_id == 518) {
"matrix_terminalb"
}
else if(object_id == 519) {
"matrix_terminalc"
}
else {
throw new IllegalArgumentException("terminal must be object id 517-519")
}
override def Buy(player : Player, msg : ItemTransactionMessage) : Terminal.Exchange = Terminal.NoDeal()
}
object MatrixTerminalDefinition {
/**
* Assemble some logic for a provided object.
* @param obj an `Amenity` object;
* anticipating a `Terminal` object using this same definition
* @param context hook to the local `Actor` system
*/
def Setup(obj : Amenity, context : ActorContext) : Unit = {
import akka.actor.{ActorRef, Props}
if(obj.Actor == ActorRef.noSender) {
obj.Actor = context.actorOf(Props(classOf[TerminalControl], obj), s"${obj.Definition.Name}_${obj.GUID.guid}")
}
}
}

View file

@ -0,0 +1,34 @@
// Copyright (c) 2017 PSForever
package net.psforever.objects.serverobject.tube
import net.psforever.objects.definition.ObjectDefinition
import net.psforever.objects.serverobject.structures.Amenity
class SpawnTube(tubeDef : ObjectDefinition) extends Amenity {
def Definition : ObjectDefinition = tubeDef
}
object SpawnTube {
def apply(tubeDef : ObjectDefinition) : SpawnTube = {
new SpawnTube(tubeDef)
}
// import akka.actor.ActorContext
// import net.psforever.types.Vector3
// /**
// * Instantiate an configure a `SpawnTube` object
// * @param pos the position (used to determine spawn point)
// * @param orient the orientation (used to indicate spawn direction)
// * @param id the unique id that will be assigned to this entity
// * @param context a context to allow the object to properly set up `ActorSystem` functionality
// * @return the `SpawnTube` object
// */
// def Constructor(pos : Vector3, orient : Vector3)(id : Int, context : ActorContext) : SpawnTube = {
// import net.psforever.objects.GlobalDefinitions
//
// val obj = SpawnTube(GlobalDefinitions.ams_respawn_tube)
// obj.Position = pos
// obj.Orientation = orient
// obj
// }
}

View file

@ -0,0 +1,17 @@
// Copyright (c) 2017 PSForever
package net.psforever.objects.serverobject.tube
import akka.actor.Actor
import net.psforever.objects.serverobject.affinity.{FactionAffinity, FactionAffinityBehavior}
/**
* An `Actor` that handles messages being dispatched to a specific `SpawnTube`.
* @param tube the `SpawnTube` object being governed
*/
class SpawnTubeControl(tube : SpawnTube) extends Actor with FactionAffinityBehavior.Check {
def FactionObject : FactionAffinity = tube
def receive : Receive = checkBehavior.orElse { case _ =>; }
override def toString : String = tube.Definition.Name
}

View file

@ -0,0 +1,26 @@
// Copyright (c) 2017 PSForever
package net.psforever.objects.serverobject.tube
import akka.actor.ActorContext
import net.psforever.objects.definition.ObjectDefinition
import net.psforever.objects.definition.converter.SpawnTubeConverter
import net.psforever.objects.serverobject.structures.Amenity
class SpawnTubeDefinition(object_id : Int) extends ObjectDefinition(object_id) {
Packet = new SpawnTubeConverter
}
object SpawnTubeDefinition {
/**
* Assemble some logic for a provided object.
* @param obj an `Amenity` object;
* anticipating a `Terminal` object using this same definition
* @param context hook to the local `Actor` system
*/
def Setup(obj : Amenity, context : ActorContext) : Unit = {
import akka.actor.{ActorRef, Props}
if(obj.Actor == ActorRef.noSender) {
obj.Actor = context.actorOf(Props(classOf[SpawnTubeControl], obj), s"${obj.Definition.Name}_${obj.GUID.guid}")
}
}
}

View file

@ -4,7 +4,8 @@ package net.psforever.objects.vehicles
import akka.actor.ActorContext
import net.psforever.objects.{GlobalDefinitions, Vehicle}
import net.psforever.objects.serverobject.structures.Amenity
import net.psforever.objects.serverobject.terminals.{OrderTerminalABDefinition, Terminal}
import net.psforever.objects.serverobject.terminals.{MatrixTerminalDefinition, OrderTerminalABDefinition, Terminal, TerminalDefinition}
import net.psforever.objects.serverobject.tube.{SpawnTube, SpawnTubeDefinition}
/**
* An `Enumeration` of the available vehicular utilities.<br>
@ -17,6 +18,8 @@ import net.psforever.objects.serverobject.terminals.{OrderTerminalABDefinition,
object UtilityType extends Enumeration {
type Type = Value
val
ams_respawn_tube,
matrix_terminalc,
order_terminala,
order_terminalb
= Value
@ -83,10 +86,32 @@ object Utility {
* @return the `Amenity` object
*/
private def BuildUtilityFunc(util : UtilityType.Value) : Amenity = util match {
case UtilityType.ams_respawn_tube =>
new SpawnTubeUtility(GlobalDefinitions.ams_respawn_tube)
case UtilityType.matrix_terminalc =>
new TerminalUtility(GlobalDefinitions.matrix_terminalc)
case UtilityType.order_terminala =>
Terminal(GlobalDefinitions.order_terminala)
new TerminalUtility(GlobalDefinitions.order_terminala)
case UtilityType.order_terminalb =>
Terminal(GlobalDefinitions.order_terminalb)
new TerminalUtility(GlobalDefinitions.order_terminalb)
}
/**
* Override for `SpawnTube` objects so that they inherit the spatial characteristics of their `Owner`.
* @param tubeDef the `ObjectDefinition` that constructs this object and maintains some of its immutable fields
*/
private class SpawnTubeUtility(tubeDef : SpawnTubeDefinition) extends SpawnTube(tubeDef) {
override def Position = Owner.Position
override def Orientation = Owner.Orientation
}
/**
* Override for `Terminal` objects so that they inherit the spatial characteristics of their `Owner`.
* @param tdef the `ObjectDefinition` that constructs this object and maintains some of its immutable fields
*/
private class TerminalUtility(tdef : TerminalDefinition) extends Terminal(tdef) {
override def Position = Owner.Position
override def Orientation = Owner.Orientation
}
/**
@ -95,6 +120,10 @@ object Utility {
* @return the `Amenity` object
*/
private def SelectUtilitySetupFunc(util : UtilityType.Value) : UtilLogic = util match {
case UtilityType.ams_respawn_tube =>
SpawnTubeDefinition.Setup
case UtilityType.matrix_terminalc =>
MatrixTerminalDefinition.Setup
case UtilityType.order_terminala =>
OrderTerminalABDefinition.Setup
case UtilityType.order_terminalb =>

View file

@ -332,7 +332,7 @@ object GamePacketOpcode extends Enumeration {
case 0x09 => game.HitMessage.decode
case 0x0a => game.HitHint.decode
case 0x0b => noDecoder(DamageMessage)
case 0x0c => noDecoder(DestroyMessage)
case 0x0c => game.DestroyMessage.decode
case 0x0d => game.ReloadMessage.decode
case 0x0e => game.MountVehicleMsg.decode
case 0x0f => game.DismountVehicleMsg.decode
@ -406,7 +406,7 @@ object GamePacketOpcode extends Enumeration {
// 0x48
case 0x48 => game.TimeOfDayMessage.decode
case 0x49 => noDecoder(UnknownMessage73)
case 0x4a => noDecoder(SpawnRequestMessage)
case 0x4a => game.SpawnRequestMessage.decode
case 0x4b => game.DeployRequestMessage.decode
case 0x4c => noDecoder(UnknownMessage76)
case 0x4d => game.RepairMessage.decode

View file

@ -1,23 +1,36 @@
// Copyright (c) 2017 PSForever
package net.psforever.packet.game
import net.psforever.packet.{GamePacketOpcode, Marshallable, PlanetSideGamePacket}
import net.psforever.packet.{GamePacketOpcode, Marshallable, PacketHelpers, PlanetSideGamePacket}
import net.psforever.types.Vector3
import scodec.Codec
import scodec.codecs._
object DeadState extends Enumeration {
type Type = Value
val
Nothing,
Dead,
Release,
RespawnTime
= Value
implicit val codec = PacketHelpers.createEnumerationCodec(this, uintL(3))
}
/**
* na
* @param unk1 0 = nothing, 1 = waiting for a rez, 2 = auto map to select spawn, 3 = respawn time
* @param unk2 na
* @param unk3 spawn penality
* @param pos last victim's position
* @param state avatar's relationship with the world
* @param timer_max total length of respawn countdown, in milliseconds
* @param timer initial length of the respawn timer, in milliseconds
* @param pos last position
* @param unk4 na
* @param unk5 na
*/
final case class AvatarDeadStateMessage(unk1 : Int,
unk2 : Long,
unk3 : Long,
final case class AvatarDeadStateMessage(state : DeadState.Value,
timer_max : Long,
timer : Long,
pos : Vector3,
unk4 : Long,
unk5 : Boolean)
@ -29,9 +42,9 @@ final case class AvatarDeadStateMessage(unk1 : Int,
object AvatarDeadStateMessage extends Marshallable[AvatarDeadStateMessage] {
implicit val codec : Codec[AvatarDeadStateMessage] = (
("unk1" | uintL(3)) ::
("unk2" | uint32L) ::
("unk3" | uint32L) ::
("state" | DeadState.codec) ::
("timer_max" | uint32L) ::
("timer" | uint32L) ::
("pos" | Vector3.codec_pos) ::
("unk4" | uint32L) ::
("unk5" | bool)

View file

@ -0,0 +1,26 @@
// Copyright (c) 2017 PSForever
package net.psforever.packet.game
import net.psforever.packet.{GamePacketOpcode, Marshallable, PlanetSideGamePacket}
import net.psforever.types.Vector3
import scodec.Codec
import scodec.codecs._
final case class DestroyMessage(unk1 : PlanetSideGUID,
unk2 : PlanetSideGUID,
unk3 : PlanetSideGUID,
pos : Vector3)
extends PlanetSideGamePacket {
type Packet = DestroyMessage
def opcode = GamePacketOpcode.DestroyMessage
def encode = DestroyMessage.encode(this)
}
object DestroyMessage extends Marshallable[DestroyMessage] {
implicit val codec : Codec[DestroyMessage] = (
("unk1" | PlanetSideGUID.codec) ::
("unk2" | PlanetSideGUID.codec) ::
("unk3" | PlanetSideGUID.codec) ::
("pos" | Vector3.codec_pos)
).as[DestroyMessage]
}

View file

@ -6,6 +6,37 @@ import scodec.Codec
import scodec.codecs._
/**
* na<br>
* Global:<br>
* `50 - Common Initialization?`<br>
* `51 - Common Initialization?`<br>
* `67 - ???`<br>
* <br>
* Global (GUID=0)<br>
* `82 - ???`
* `83 - max boomers`<br>
* `84 - max he mines`<br>
* `85 - max disruptor mines`<br>
* `86 - max spitfire turrets`<br>
* `87 - max motion sensors`<br>
* `88 - max shadow turrets`<br>
* `89 - max cerebus turrets`<br>
* `90 - max Aegis shield generators`<br>
* `91 - max TRAPs`<br>
* `92 - max OMFTs`<br>
* `93 - max sensor disruptors`<br>
* `94 - boomers`<br>
* `95 - he mines`<br>
* `96 - disruptor mines`<br>
* `97 - spitfire turrets`<br>
* `98 - motion sensors`<br>
* `99 - shadow turrets`<br>
* `100 - cerebus turrets`<br>
* `101 - Aegis shield generators`<br>
* `102 - TRAPSs`<br>
* `103 - OMFTs`<br>
* `104 - sensor disruptors`<br>
* <br>
* Players/General:<br>
* Server to client : <br>
* `0 - health`<br>
@ -74,31 +105,33 @@ import scodec.codecs._
* `36 - CR. Value is the CR`<br>
* `43 - Info on avatar name : 0 = Nothing, 1 = "(LD)" message`<br>
* `53 - LFS. Value is 1 to flag LFS`<br>
* `54 - Player "Aura". Values are : 0 for nothing, 1 for plasma, 2 for ancient, 3 for plasma + ancient,<br>
* 4 for LLU?, 5 for plasma + LLU?, 6 for ancient + LLU?, 7 for plasma + ancient + LLU?, 8 for fire,<br>
* 9 for plasma + fire, 10 for ancient + fire, 11 for plasma + ancient + fire,<br>
* 12 for LLU? + fire, 13 for plasma + LLU? + fire, 14 for ancient + LLU? + fire,<br>
* 15 for plasma + ancient + LLU? + fire,`<br>
* `54 - Player "Aura". Values can be expressed in the first byte's lower nibble:`<br>
* - 0 is nothing<br>
* - 1 is plasma<br>
* - 2 is ancient<br>
* - 4 is LLU (?)<br>
* - 8 is fire<br>
* -- 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>
* `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>
* `106 - Custom Head`
* `106 - Custom Head`<br>
* Client to Server : <br>
* `106 - Custom Head`<br>
* <br>
* Vehicles:<br>
* 0 - Vehicle base health<br>
* 10 - Driver seat permissions (0 = Locked, 1 = Group, 3 = Empire)<br>
* 11 - Gunner seat(s) permissions (same)<br>
* 12 - Passenger seat(s) permissions (same) <br>
* 13 - Trunk permissions (same)<br>
* 21 - Asserts first time event eligibility / makes owner if no owner is assigned<br>
* 22 - Toggles gunner and passenger mount points (1 = hides, 0 = reveals; this also locks their permissions)<br>
* 68 - ???<br>
* 80 - Damage vehicle (unknown value)<br>
* 113 - ???
* `Vehicles:`<br>
* `10 - Driver seat permissions (0 = Locked, 1 = Group, 3 = Empire)`<br>
* `11 - Gunner seat(s) permissions (same)`<br>
* `12 - Passenger seat(s) permissions (same)`<br>
* `13 - Trunk permissions (same)`<br>
* `21 - Asserts first time event eligibility / makes owner if no owner is assigned`<br>
* `22 - Toggles gunner and passenger mount points (1 = hides, 0 = reveals; this also locks their permissions)`<br>
* `68 - ???`<br>
* `80 - Damage vehicle (unknown value)`<br>
* `81 - ???`<br>
* `113 - ???`
* @param player_guid the player
* @param attribute_type na
* @param attribute_value na

View file

@ -0,0 +1,28 @@
// Copyright (c) 2017 PSForever
package net.psforever.packet.game
import net.psforever.packet.{GamePacketOpcode, Marshallable, PlanetSideGamePacket}
import scodec.Codec
import scodec.codecs._
final case class SpawnRequestMessage(unk1 : Int,
unk2 : Long,
unk3 : Int,
unk4 : Int,
unk5 : Int)
extends PlanetSideGamePacket {
type Packet = SpawnRequestMessage
def opcode = GamePacketOpcode.SpawnRequestMessage
def encode = SpawnRequestMessage.encode(this)
}
object SpawnRequestMessage extends Marshallable[SpawnRequestMessage] {
implicit val codec : Codec[SpawnRequestMessage] = (
("unk1" | uint16L) ::
("unk2" | uint32L) ::
("unk3" | uint16L) ::
("unk4" | uint16L) ::
("unk5" | uintL(10))
).as[SpawnRequestMessage]
}

View file

@ -13,7 +13,7 @@ class AvatarDeadStateMessageTest extends Specification {
"decode" in {
PacketCoding.DecodePacket(string).require match {
case AvatarDeadStateMessage(unk1,unk2,unk3,pos,unk4,unk5) =>
unk1 mustEqual 1
unk1 mustEqual DeadState.Dead
unk2 mustEqual 300000
unk3 mustEqual 300000
pos mustEqual Vector3(6552.617f,4602.375f,60.90625f)
@ -25,7 +25,7 @@ class AvatarDeadStateMessageTest extends Specification {
}
"encode" in {
val msg = AvatarDeadStateMessage(1, 300000, 300000, Vector3(6552.617f,4602.375f,60.90625f), 2, true)
val msg = AvatarDeadStateMessage(DeadState.Dead, 300000, 300000, Vector3(6552.617f,4602.375f,60.90625f), 2, true)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string

View file

@ -0,0 +1,33 @@
// Copyright (c) 2017 PSForever
package game
import org.specs2.mutable._
import net.psforever.packet._
import net.psforever.packet.game._
import net.psforever.types.Vector3
import scodec.bits._
class DestroyMessageTest extends Specification {
val string = hex"0C 74 09 74 09 00 00 06 35 3C FF D7 26 08"
"DestroyMessage" should {
"decode" in {
PacketCoding.DecodePacket(string).require match {
case DestroyMessage(unk1, unk2, unk3, pos) =>
unk1 mustEqual PlanetSideGUID(2420)
unk2 mustEqual PlanetSideGUID(2420)
unk3 mustEqual PlanetSideGUID(0)
pos mustEqual Vector3(1642.0469f, 4091.6172f, 32.59375f)
case _ =>
ko
}
}
"encode" in {
val msg = DestroyMessage(PlanetSideGUID(2420), PlanetSideGUID(2420), PlanetSideGUID(0), Vector3(1642.0469f, 4091.6172f, 32.59375f))
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string
}
}
}

View file

@ -0,0 +1,31 @@
// Copyright (c) 2017 PSForever
package game
import org.specs2.mutable._
import net.psforever.packet._
import net.psforever.packet.game._
import scodec.bits._
class SpawnRequestMessageTest extends Specification {
val string = hex"4a000007000000000000000200"
"decode" in {
PacketCoding.DecodePacket(string).require match {
case SpawnRequestMessage(unk1,unk2,unk3,unk4,unk5) =>
unk1 mustEqual 0
unk2 mustEqual 7
unk3 mustEqual 0
unk4 mustEqual 0
unk5 mustEqual 2
case _ =>
ko
}
}
"encode" in {
val msg = SpawnRequestMessage(0, 7, 0, 0, 2)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string
}
}

View file

@ -1,7 +1,6 @@
// Copyright (c) 2017 PSForever
package objects
import net.psforever.objects.GlobalDefinitions.remote_electronics_kit
import net.psforever.objects.definition.converter.{ACEConverter, CharacterSelectConverter, REKConverter}
import net.psforever.objects._
import net.psforever.objects.definition._
@ -9,6 +8,7 @@ import net.psforever.objects.equipment.CItem.{DeployedItem, Unit}
import net.psforever.objects.equipment._
import net.psforever.objects.inventory.InventoryTile
import net.psforever.objects.serverobject.terminals.Terminal
import net.psforever.objects.serverobject.tube.SpawnTube
import net.psforever.packet.game.PlanetSideGUID
import net.psforever.packet.game.objectcreate._
import net.psforever.types.{CharacterGender, PlanetSideEmpire, Vector3}
@ -184,13 +184,13 @@ class ConverterTest extends Specification {
"convert to packet (BR < 24)" in {
obj.BEP = 0
obj.Definition.Packet.DetailedConstructorData(obj) match {
case Success(pkt) =>
case Success(_) =>
ok
case _ =>
ko
}
obj.Definition.Packet.ConstructorData(obj) match {
case Success(pkt) =>
case Success(_) =>
ok
case _ =>
ko
@ -200,13 +200,13 @@ class ConverterTest extends Specification {
"convert to packet (BR >= 24)" in {
obj.BEP = 10000000
obj.Definition.Packet.DetailedConstructorData(obj) match {
case Success(pkt) =>
case Success(_) =>
ok
case _ =>
ko
}
obj.Definition.Packet.ConstructorData(obj) match {
case Success(pkt) =>
case Success(_) =>
ok
case _ =>
ko
@ -216,7 +216,7 @@ class ConverterTest extends Specification {
"convert to simple packet (BR < 24)" in {
obj.BEP = 0
converter.DetailedConstructorData(obj) match {
case Success(pkt) =>
case Success(_) =>
ok
case _ =>
ko
@ -228,7 +228,7 @@ class ConverterTest extends Specification {
"convert to simple packet (BR >= 24)" in {
obj.BEP = 10000000
converter.DetailedConstructorData(obj) match {
case Success(pkt) =>
case Success(_) =>
ok
case _ =>
ko
@ -290,7 +290,27 @@ class ConverterTest extends Specification {
obj.Definition.Packet.ConstructorData(obj) match {
case Success(pkt) =>
pkt mustEqual CommonTerminalData(PlanetSideEmpire.NEUTRAL, 0)
pkt mustEqual CommonTerminalData(PlanetSideEmpire.NEUTRAL)
case _ =>
ko
}
}
}
"Spawn Tube" should {
"convert to packet" in {
val obj = SpawnTube(GlobalDefinitions.ams_respawn_tube)
obj.Definition.Packet.DetailedConstructorData(obj) match {
case Failure(err) =>
err.isInstanceOf[NoSuchMethodException] mustEqual true
case _ =>
ko
}
obj.Definition.Packet.ConstructorData(obj) match {
case Success(pkt) =>
pkt mustEqual CommonTerminalData(PlanetSideEmpire.NEUTRAL)
case _ =>
ko
}
@ -338,8 +358,10 @@ class ConverterTest extends Specification {
val
ams = Vehicle(GlobalDefinitions.ams)
ams.GUID = PlanetSideGUID(413)
ams.Utilities(3)().GUID = PlanetSideGUID(414)
ams.Utilities(4)().GUID = PlanetSideGUID(415)
ams.Utilities(1)().GUID = PlanetSideGUID(414)
ams.Utilities(2)().GUID = PlanetSideGUID(415)
ams.Utilities(3)().GUID = PlanetSideGUID(416)
ams.Utilities(4)().GUID = PlanetSideGUID(417)
ams.Definition.Packet.ConstructorData(ams).isSuccess mustEqual true
ok //TODO write more of this test

View file

@ -27,6 +27,49 @@ class UtilityTest extends Specification {
obj().asInstanceOf[Terminal].Definition.ObjectId mustEqual 614
obj().asInstanceOf[Terminal].Actor == ActorRef.noSender
}
"create a matrix_terminalc object" in {
val obj = Utility(UtilityType.matrix_terminalc, UtilityTest.vehicle)
obj.UtilType mustEqual UtilityType.matrix_terminalc
obj().isInstanceOf[Terminal] mustEqual true
obj().asInstanceOf[Terminal].Definition.ObjectId mustEqual 519
obj().asInstanceOf[Terminal].Actor == ActorRef.noSender
}
"create an ams_respawn_tube object" in {
import net.psforever.objects.serverobject.tube.SpawnTube
val obj = Utility(UtilityType.ams_respawn_tube, UtilityTest.vehicle)
obj.UtilType mustEqual UtilityType.ams_respawn_tube
obj().isInstanceOf[SpawnTube] mustEqual true
obj().asInstanceOf[SpawnTube].Definition.ObjectId mustEqual 49
obj().asInstanceOf[SpawnTube].Actor == ActorRef.noSender
}
"be located with their owner (terminal)" in {
val veh = Vehicle(GlobalDefinitions.quadstealth)
val obj = Utility(UtilityType.order_terminala, veh)
obj().Position mustEqual veh.Position
obj().Orientation mustEqual veh.Orientation
import net.psforever.types.Vector3
veh.Position = Vector3(1, 2, 3)
veh.Orientation = Vector3(4, 5, 6)
obj().Position mustEqual veh.Position
obj().Orientation mustEqual veh.Orientation
}
"be located with their owner (spawn tube)" in {
val veh = Vehicle(GlobalDefinitions.quadstealth)
val obj = Utility(UtilityType.ams_respawn_tube, veh)
obj().Position mustEqual veh.Position
obj().Orientation mustEqual veh.Orientation
import net.psforever.types.Vector3
veh.Position = Vector3(1, 2, 3)
veh.Orientation = Vector3(4, 5, 6)
obj().Position mustEqual veh.Position
obj().Orientation mustEqual veh.Orientation
}
}
}
@ -58,6 +101,34 @@ class Utility2Test extends ActorTest() {
}
}
class Utility3Test extends ActorTest() {
"Utility" should {
"wire a matrix_terminalc Actor" in {
val obj = Utility(UtilityType.matrix_terminalc, UtilityTest.vehicle)
obj().GUID = PlanetSideGUID(1)
assert(obj().Actor == ActorRef.noSender)
system.actorOf(Props(classOf[UtilityTest.SetupControl], obj), "test") ! ""
receiveOne(Duration.create(100, "ms")) //consume and discard
assert(obj().Actor != ActorRef.noSender)
}
}
}
class Utility4Test extends ActorTest() {
"Utility" should {
"wire an ams_respawn_tube Actor" in {
val obj = Utility(UtilityType.ams_respawn_tube, UtilityTest.vehicle)
obj().GUID = PlanetSideGUID(1)
assert(obj().Actor == ActorRef.noSender)
system.actorOf(Props(classOf[UtilityTest.SetupControl], obj), "test") ! ""
receiveOne(Duration.create(100, "ms")) //consume and discard
assert(obj().Actor != ActorRef.noSender)
}
}
}
object UtilityTest {
val vehicle = Vehicle(GlobalDefinitions.quadstealth)

View file

@ -0,0 +1,63 @@
// Copyright (c) 2017 PSForever
package objects.terminal
import akka.actor.ActorRef
import net.psforever.objects.serverobject.terminals.{MatrixTerminalDefinition, Terminal}
import net.psforever.objects.{GlobalDefinitions, Player, Vehicle}
import net.psforever.packet.game.{ItemTransactionMessage, PlanetSideGUID}
import net.psforever.types._
import org.specs2.mutable.Specification
class MatrixTerminalTest extends Specification {
"MatrixTerminal" should {
"define (a)" in {
val a = new MatrixTerminalDefinition(517)
a.ObjectId mustEqual 517
a.Name mustEqual "matrix_terminala"
}
"define (b)" in {
val b = new MatrixTerminalDefinition(518)
b.ObjectId mustEqual 518
b.Name mustEqual "matrix_terminalb"
}
"define (b)" in {
val b = new MatrixTerminalDefinition(519)
b.ObjectId mustEqual 519
b.Name mustEqual "matrix_terminalc"
}
"define (invalid)" in {
var id : Int = (math.random * Int.MaxValue).toInt
if(id == 517) {
id += 3
}
else if(id == 518) {
id += 2
}
else if(id == 519) {
id += 1
}
new MatrixTerminalDefinition(id) must throwA[IllegalArgumentException]
}
}
"Matrix_Terminal" should {
val terminal = Terminal(GlobalDefinitions.matrix_terminalc)
terminal.Owner = Vehicle(GlobalDefinitions.quadstealth)
terminal.Owner.Faction = PlanetSideEmpire.TR
"construct" in {
terminal.Actor mustEqual ActorRef.noSender
}
"player can not buy (anything)" in {
val player = Player("test", PlanetSideEmpire.TR, CharacterGender.Male, 0, 0)
val msg = ItemTransactionMessage(PlanetSideGUID(1), TransactionType.Buy, 1, "lite_armor", 0, PlanetSideGUID(0))
terminal.Request(player, msg) mustEqual Terminal.NoDeal()
}
}
}

View file

@ -22,7 +22,18 @@ object Maps {
val map5 = new ZoneMap("map05")
val map6 = new ZoneMap("map06")
val map6 = new ZoneMap("map06") {
//TODO TEST ceryshen
LocalObject(ServerObjectBuilder(3353, Terminal.Constructor(ground_vehicle_terminal)))
LocalObject(ServerObjectBuilder(500,
VehicleSpawnPad.Constructor(Vector3(3962.0f, 4334.0f, 268.0f), Vector3(0f, 0f, 180.0f))
)) //TODO guid not correct
LocalBuilding(2, FoundationBuilder(Building.Structure))
ObjectToBuilding(3353, 2)
ObjectToBuilding(500, 2)
TerminalToSpawnPad(3353, 500)
}
val map7 = new ZoneMap("map07")

View file

@ -23,8 +23,9 @@ import net.psforever.objects.serverobject.implantmech.ImplantTerminalMech
import net.psforever.objects.serverobject.locks.IFFLock
import net.psforever.objects.serverobject.mblocker.Locker
import net.psforever.objects.serverobject.pad.VehicleSpawnPad
import net.psforever.objects.serverobject.terminals.Terminal
import net.psforever.objects.vehicles.{AccessPermissionGroup, VehicleLockState}
import net.psforever.objects.serverobject.terminals.{MatrixTerminalDefinition, Terminal}
import net.psforever.objects.serverobject.terminals.Terminal.TerminalMessage
import net.psforever.objects.vehicles.{AccessPermissionGroup, Utility, VehicleLockState}
import net.psforever.objects.zones.{InterstellarCluster, Zone}
import net.psforever.packet.game.objectcreate._
import net.psforever.types._
@ -402,16 +403,17 @@ class WorldSessionActor extends Actor with MDCContextAware {
val vehicle_guid = obj.GUID
if(state == DriveState.Deploying) {
log.info(s"DeployRequest: $obj transitioning to deploy state")
sendResponse(DeployRequestMessage(player.GUID, vehicle_guid, state, 0, false, obj.Position))
vehicleService ! VehicleServiceMessage(continent.Id, VehicleAction.DeployRequest(player.GUID, vehicle_guid, state, 0, false, obj.Position))
obj.Velocity = Some(Vector3.Zero) //no velocity
sendResponse(DeployRequestMessage(player.GUID, vehicle_guid, state, 0, false, Vector3.Zero))
vehicleService ! VehicleServiceMessage(continent.Id, VehicleAction.DeployRequest(player.GUID, vehicle_guid, state, 0, false, Vector3.Zero))
import scala.concurrent.duration._
import scala.concurrent.ExecutionContext.Implicits.global
context.system.scheduler.scheduleOnce(obj.DeployTime milliseconds, obj.Actor, Deployment.TryDeploy(DriveState.Deployed))
}
else if(state == DriveState.Deployed) {
log.info(s"DeployRequest: $obj has been Deployed")
sendResponse(DeployRequestMessage(player.GUID, vehicle_guid, state, 0, false, obj.Position))
vehicleService ! VehicleServiceMessage(continent.Id, VehicleAction.DeployRequest(player.GUID, vehicle_guid, state, 0, false, obj.Position))
sendResponse(DeployRequestMessage(player.GUID, vehicle_guid, state, 0, false, Vector3.Zero))
vehicleService ! VehicleServiceMessage(continent.Id, VehicleAction.DeployRequest(player.GUID, vehicle_guid, state, 0, false, Vector3.Zero))
DeploymentActivities(obj)
//...
}
@ -902,8 +904,9 @@ class WorldSessionActor extends Actor with MDCContextAware {
continent.Transport ! Zone.SpawnVehicle(vehicle)
vehicleService ! VehicleServiceMessage(continent.Id, VehicleAction.LoadVehicle(player_guid, vehicle, objedtId, vehicle_guid, vdata))
sendResponse(PlanetsideAttributeMessage(vehicle_guid, 22, 1L)) //mount points off?
//sendResponse(PlanetsideAttributeMessage(vehicle_guid, 21, player_guid.guid))) //fte and ownership?
//sendResponse(ObjectAttachMessage(vehicle_guid, player_guid, 0)))
sendResponse(PlanetsideAttributeMessage(vehicle_guid, 22, 1L)) //mount points off?
sendResponse(PlanetsideAttributeMessage(vehicle_guid, 21, player_guid.guid)) //fte and ownership?
//sendResponse(ObjectAttachMessage(vehicle_guid, player_guid, 0))
vehicleService ! VehicleServiceMessage.UnscheduleDeconstruction(vehicle_guid) //cancel queue timeout delay
vehicleService ! VehicleServiceMessage.DelayedVehicleDeconstruction(vehicle, continent, 21L) //temporary drive away from pad delay
vehicle.Actor ! Mountable.TryMount(player, 0)
@ -980,13 +983,13 @@ class WorldSessionActor extends Actor with MDCContextAware {
PlanetSideGUID(6), //Ceryshen
PlanetSideGUID(2), //Anguta
8, //80% NTU
true, //Base hacked
PlanetSideEmpire.NC, //Base hacked by NC
600000, //10 minutes remaining for hack
false, //Base hacked
PlanetSideEmpire.NEUTRAL, //Base hacked by NC
0, //10 minutes remaining for hack
PlanetSideEmpire.VS, //Base owned by VS
0, //!! Field != 0 will cause malformed packet. See class def.
None,
PlanetSideGeneratorState.Critical, //Generator critical
PlanetSideGeneratorState.Normal, //Generator critical
true, //Respawn tubes destroyed
true, //Force dome active
16, //Tech plant lattice benefit
@ -1022,6 +1025,11 @@ class WorldSessionActor extends Actor with MDCContextAware {
sendResponse(SetCurrentAvatarMessage(guid,0,0))
sendResponse(CreateShortcutMessage(guid, 1, 0, true, Shortcut.MEDKIT))
sendResponse(ChatMsg(ChatMessageType.CMT_EXPANSIONS, true, "", "1 on", None)) //CC on
sendResponse(PlanetsideAttributeMessage(PlanetSideGUID(0), 82, 0))
(1 to 73).foreach( i => {
sendResponse(PlanetsideAttributeMessage(PlanetSideGUID(i), 67, 0))
})
case Zone.ItemFromGround(tplayer, item) =>
val obj_guid = item.GUID
@ -1234,13 +1242,18 @@ class WorldSessionActor extends Actor with MDCContextAware {
log.info("Reticulating splines ...")
//map-specific initializations
//TODO continent.ClientConfiguration()
sendResponse(PlanetsideAttributeMessage(PlanetSideGUID(0), 112, 1))
sendResponse(SetEmpireMessage(PlanetSideGUID(2), PlanetSideEmpire.VS)) //HART building C
sendResponse(SetEmpireMessage(PlanetSideGUID(29), PlanetSideEmpire.NC)) //South Villa Gun Tower
sendResponse(TimeOfDayMessage(1191182336))
sendResponse(ReplicationStreamMessage(5, Some(6), Vector(SquadListing()))) //clear squad list
//render Equipment that was dropped into zone before the player arrived
sendResponse(ZonePopulationUpdateMessage(PlanetSideGUID(6), 414, 138, 0, 138, 0, 138, 0, 138, 0))
(1 to 255).foreach(i => { sendResponse(SetEmpireMessage(PlanetSideGUID(i), PlanetSideEmpire.VS)) })
//render Equipment that was dropped into zone before the player arrived
continent.EquipmentOnGround.foreach(item => {
val definition = item.Definition
sendResponse(
@ -1387,14 +1400,31 @@ class WorldSessionActor extends Actor with MDCContextAware {
case msg @ ProjectileStateMessage(projectile_guid, shot_pos, shot_vector, unk1, unk2, unk3, unk4, time_alive) =>
//log.info("ProjectileState: " + msg)
case msg @ ReleaseAvatarRequestMessage() =>
log.info(s"ReleaseAvatarRequest: ${player.GUID} on ${continent.Id} has released")
sendResponse(PlanetsideAttributeMessage(player.GUID, 6, 1))
sendResponse(AvatarDeadStateMessage(DeadState.Release, 0, 0, player.Position, 2, true))
case msg @ SpawnRequestMessage(u1, u2, u3, u4, u5) =>
log.info(s"SpawnRequestMessage: $msg")
case msg @ ChatMsg(messagetype, has_wide_contents, recipient, contents, note_contents) =>
// TODO: Prevents log spam, but should be handled correctly
if (messagetype != ChatMessageType.CMT_TOGGLE_GM) {
log.info("Chat: " + msg)
}
if(messagetype == ChatMessageType.CMT_SUICIDE) {
val player_guid = player.GUID
val pos = player.Position
sendResponse(PlanetsideAttributeMessage(player_guid, 0, 0))
sendResponse(PlanetsideAttributeMessage(player_guid, 2, 0))
sendResponse(DestroyMessage(player_guid, player_guid, PlanetSideGUID(0), pos))
sendResponse(AvatarDeadStateMessage(DeadState.Dead, 300000, 300000, pos, 2, true))
}
if (messagetype == ChatMessageType.CMT_VOICE) {
sendResponse(ChatMsg(ChatMessageType.CMT_VOICE, false, "IlllIIIlllIlIllIlllIllI", contents, None))
sendResponse(ChatMsg(ChatMessageType.CMT_VOICE, false, player.Name, contents, None))
}
// TODO: handle this appropriately
@ -1944,6 +1974,15 @@ class WorldSessionActor extends Actor with MDCContextAware {
}
}
case Some(obj : Terminal) =>
if(obj.Definition.isInstanceOf[MatrixTerminalDefinition]) {
//TODO matrix spawn point; for now, just blindly bind to show work (and hope nothing breaks)
sendResponse(BindPlayerMessage(1, "@ams", true, true, 0, 0, 0, obj.Position))
}
else {
sendResponse(UseItemMessage(avatar_guid, unk1, object_guid, unk2, unk3, unk4, unk5, unk6, unk7, unk8, itemType))
}
case Some(obj : PlanetSideGameObject) =>
if(itemType != 121) {
sendResponse(UseItemMessage(avatar_guid, unk1, object_guid, unk2, unk3, unk4, unk5, unk6, unk7, unk8, itemType))
@ -2986,8 +3025,8 @@ class WorldSessionActor extends Actor with MDCContextAware {
def DeploymentActivities(obj : Deployment.DeploymentObject) : Unit = {
obj match {
case vehicle : Vehicle =>
//TODO we should not have to do this imho
ReloadVehicleAccessPermissions(vehicle)
ReloadVehicleAccessPermissions(vehicle) //TODO we should not have to do this imho
sendResponse(PlanetsideAttributeMessage(obj.GUID, 81, 1))
case _ => ;
}
}

View file

@ -13,7 +13,14 @@ object Zones {
val z5 = new Zone("z5", Maps.map5, 5)
val z6 = new Zone("z6", Maps.map6, 6)
val z6 = new Zone("z6", Maps.map6, 6) {
override def Init(implicit context : ActorContext) : Unit = {
super.Init(context)
import net.psforever.types.PlanetSideEmpire
Building(2).get.Faction = PlanetSideEmpire.VS
}
}
val z7 = new Zone("z7", Maps.map7, 7)