From 110dcdf6750d1992978f67127dc2ca6c1767c366 Mon Sep 17 00:00:00 2001 From: FateJH Date: Wed, 30 Aug 2017 09:35:18 -0400 Subject: [PATCH 1/5] added DetailedLockerContainerData Codec; modified PacketConverter for LockerContainer; modified tests --- .../converter/LockerContainerConverter.scala | 6 +- .../DetailedLockerContainerData.scala | 89 +++++++++++++++++++ .../game/objectcreate/InventoryData.scala | 4 +- .../game/objectcreate/ObjectClass.scala | 2 +- .../ObjectCreateDetailedMessageTest.scala | 7 +- 5 files changed, 100 insertions(+), 8 deletions(-) create mode 100644 common/src/main/scala/net/psforever/packet/game/objectcreate/DetailedLockerContainerData.scala diff --git a/common/src/main/scala/net/psforever/objects/definition/converter/LockerContainerConverter.scala b/common/src/main/scala/net/psforever/objects/definition/converter/LockerContainerConverter.scala index 0ef5205b..8c578331 100644 --- a/common/src/main/scala/net/psforever/objects/definition/converter/LockerContainerConverter.scala +++ b/common/src/main/scala/net/psforever/objects/definition/converter/LockerContainerConverter.scala @@ -5,7 +5,7 @@ import net.psforever.objects.LockerContainer import net.psforever.objects.equipment.Equipment import net.psforever.objects.inventory.GridInventory import net.psforever.packet.game.PlanetSideGUID -import net.psforever.packet.game.objectcreate.{DetailedAmmoBoxData, InternalSlot, InventoryData, LockerContainerData} +import net.psforever.packet.game.objectcreate._ import scala.util.{Success, Try} @@ -14,8 +14,8 @@ class LockerContainerConverter extends ObjectCreateConverter[LockerContainer]() Success(LockerContainerData(InventoryData(MakeInventory(obj.Inventory)))) } - override def DetailedConstructorData(obj : LockerContainer) : Try[DetailedAmmoBoxData] = { - Success(DetailedAmmoBoxData(8, 1)) //same format as AmmoBox data + override def DetailedConstructorData(obj : LockerContainer) : Try[DetailedLockerContainerData] = { + Success(DetailedLockerContainerData(8)) } /** diff --git a/common/src/main/scala/net/psforever/packet/game/objectcreate/DetailedLockerContainerData.scala b/common/src/main/scala/net/psforever/packet/game/objectcreate/DetailedLockerContainerData.scala new file mode 100644 index 00000000..ef60dcb6 --- /dev/null +++ b/common/src/main/scala/net/psforever/packet/game/objectcreate/DetailedLockerContainerData.scala @@ -0,0 +1,89 @@ +// Copyright (c) 2017 PSForever +package net.psforever.packet.game.objectcreate + +import net.psforever.packet.Marshallable +import net.psforever.packet.game.PlanetSideGUID +import scodec.codecs._ +import scodec.{Attempt, Codec, Err} +import shapeless.{::, HNil} + +/** + * A representation of the inventory portion of `ObjectCreateDetailedMessage` packet data that contains the items in the avatar's locker space.
+ *
+ * Although these items are technically always loaded and registered with globally unique identifiers for the current zone, + * the actual container for them, in grid format, can only be accessed by interacting with locker objects in the game world. + * Items are generally added and removed in the same way as with any other opened inventory. + * Unlike other inventories, however, locker space is personal to an avatar and can not be accessed by other players. + * @param unk na + * @param contents the items in the inventory + */ +final case class DetailedLockerContainerData(unk : Int, + contents : Option[List[InternalSlot]] + ) extends ConstructorData { + override def bitsize : Long = { + val base : Long = 40L + var invSize : Long = 0L //length of all items in inventory + if(contents.isDefined) { + invSize = InventoryData.BaseSize + for(item <- contents.get) { + invSize += item.bitsize + } + } + base + invSize + } +} + +object DetailedLockerContainerData extends Marshallable[DetailedLockerContainerData] { + /** + * Overloaded constructor for creating `DetailedLockerContainerData` without a list of contents. + * @param unk na + * @return a `DetailedLockerContainerData` object + */ + def apply(unk : Int) : DetailedLockerContainerData = + new DetailedLockerContainerData(unk, None) + + /** + * Overloaded constructor for creating `DetailedLockerContainerData` containing known items. + * @param unk na + * @param contents the items in the inventory + * @return a `DetailedLockerContainerData` object + */ + def apply(unk : Int, contents : List[InternalSlot]) : DetailedLockerContainerData = + new DetailedLockerContainerData(unk, Some(contents)) + + /** + * Overloaded constructor for creating `DetailedLockerContainerData` while masking use of `InternalSlot`. + * @param cls the code for the type of object being constructed + * @param guid the GUID this object will be assigned + * @param parentSlot a parent-defined slot identifier that explains where the child is to be attached to the parent + * @param locker the `DetailedLockerContainerData` + * @return an `InternalSlot` object that encapsulates `DetailedLockerContainerData` + */ + def apply(cls : Int, guid : PlanetSideGUID, parentSlot : Int, locker : DetailedLockerContainerData) : InternalSlot = + new InternalSlot(cls, guid, parentSlot, locker) + + implicit val codec : Codec[DetailedLockerContainerData] = ( + uint4L :: + ("unk" | uint4L) :: // 8 - common - 4 - safe, 2 - stream misalignment, 1 - safe, 0 - common + uint(15) :: + uint16L :: //always 1 + optional(bool, InventoryData.codec_detailed) + ).exmap[DetailedLockerContainerData] ( + { + case 0xC :: unk :: 0 :: 1 :: None :: HNil => + Attempt.successful(DetailedLockerContainerData(unk, None)) + + case 0xC :: unk :: 0 :: 1 :: Some(InventoryData(list)) :: HNil => + Attempt.successful(DetailedLockerContainerData(unk, Some(list))) + case _ => + Attempt.failure(Err(s"invalid locker container data format")) + }, + { + case DetailedLockerContainerData(unk, None) => + Attempt.successful(0xC :: unk :: 0 :: 1 :: None :: HNil) + + case DetailedLockerContainerData(unk, Some(list)) => + Attempt.successful(0xC :: unk :: 0 :: 1 :: Some(InventoryData(list)) :: HNil) + } + ) +} diff --git a/common/src/main/scala/net/psforever/packet/game/objectcreate/InventoryData.scala b/common/src/main/scala/net/psforever/packet/game/objectcreate/InventoryData.scala index f21590b4..c3c06c0f 100644 --- a/common/src/main/scala/net/psforever/packet/game/objectcreate/InventoryData.scala +++ b/common/src/main/scala/net/psforever/packet/game/objectcreate/InventoryData.scala @@ -23,7 +23,7 @@ import shapeless.{::, HNil} */ final case class InventoryData(contents : List[InventoryItem] = List.empty) extends StreamBitSize { override def bitsize : Long = { - val base : Long = 10L //8u + 1u + 1u + val base : Long = InventoryData.BaseSize var invSize : Long = 0L //length of all items in inventory for(item <- contents) { invSize += item.bitsize @@ -33,6 +33,8 @@ final case class InventoryData(contents : List[InventoryItem] = List.empty) exte } object InventoryData { + final val BaseSize : Long = 10L //8u + 1u + 1u + /** * The primary `Codec` that parses the common format for an inventory `List`. * @param itemCodec a `Codec` that describes each of the contents of the list diff --git a/common/src/main/scala/net/psforever/packet/game/objectcreate/ObjectClass.scala b/common/src/main/scala/net/psforever/packet/game/objectcreate/ObjectClass.scala index 642a9922..f88a38e7 100644 --- a/common/src/main/scala/net/psforever/packet/game/objectcreate/ObjectClass.scala +++ b/common/src/main/scala/net/psforever/packet/game/objectcreate/ObjectClass.scala @@ -638,7 +638,7 @@ object ObjectClass { case ObjectClass.boomer_trigger => ConstructorData.genericCodec(DetailedBoomerTriggerData.codec, "boomer trigger") //other case ObjectClass.avatar => ConstructorData.genericCodec(DetailedCharacterData.codec, "avatar") - case ObjectClass.locker_container => ConstructorData.genericCodec(DetailedAmmoBoxData.codec, "locker container") + case ObjectClass.locker_container => ConstructorData.genericCodec(DetailedLockerContainerData.codec, "locker container") //failure case case _ => defaultFailureCodec(objClass) diff --git a/common/src/test/scala/game/ObjectCreateDetailedMessageTest.scala b/common/src/test/scala/game/ObjectCreateDetailedMessageTest.scala index ee9e38d1..81314a8c 100644 --- a/common/src/test/scala/game/ObjectCreateDetailedMessageTest.scala +++ b/common/src/test/scala/game/ObjectCreateDetailedMessageTest.scala @@ -260,7 +260,8 @@ class ObjectCreateDetailedMessageTest extends Specification { inventory(3).objectClass mustEqual ObjectClass.locker_container inventory(3).guid mustEqual PlanetSideGUID(82) inventory(3).parentSlot mustEqual 5 - inventory(3).obj.asInstanceOf[DetailedAmmoBoxData].magazine mustEqual 1 + inventory(3).obj.isInstanceOf[DetailedLockerContainerData] mustEqual true + inventory(3).obj.asInstanceOf[DetailedLockerContainerData].contents.isDefined mustEqual false //4 inventory(4).objectClass mustEqual ObjectClass.bullet_9mm inventory(4).guid mustEqual PlanetSideGUID(83) @@ -342,7 +343,7 @@ class ObjectCreateDetailedMessageTest extends Specification { Nil )(2) val msg = ObjectCreateDetailedMessage(ObjectClass.punisher, PlanetSideGUID(1703), ObjectCreateMessageParent(PlanetSideGUID(75), 2), obj) - var pkt = PacketCoding.EncodePacket(msg).require.toByteVector + val pkt = PacketCoding.EncodePacket(msg).require.toByteVector pkt mustEqual string_punisher } @@ -394,7 +395,7 @@ class ObjectCreateDetailedMessageTest extends Specification { val inv = InventoryItemData(ObjectClass.beamer, PlanetSideGUID(76), 0, DetailedWeaponData(4, 8, ObjectClass.energy_cell, PlanetSideGUID(77), 0, DetailedAmmoBoxData(8, 16))) :: InventoryItemData(ObjectClass.suppressor, PlanetSideGUID(78), 2, DetailedWeaponData(4, 8, ObjectClass.bullet_9mm, PlanetSideGUID(79), 0, DetailedAmmoBoxData(8, 25))) :: InventoryItemData(ObjectClass.forceblade, PlanetSideGUID(80), 4, DetailedWeaponData(4, 8, ObjectClass.melee_ammo, PlanetSideGUID(81), 0, DetailedAmmoBoxData(8, 1))) :: - InventoryItemData(ObjectClass.locker_container, PlanetSideGUID(82), 5, DetailedAmmoBoxData(8, 1)) :: + InventoryItemData(ObjectClass.locker_container, PlanetSideGUID(82), 5, DetailedLockerContainerData(8)) :: InventoryItemData(ObjectClass.bullet_9mm, PlanetSideGUID(83), 6, DetailedAmmoBoxData(8, 50)) :: InventoryItemData(ObjectClass.bullet_9mm, PlanetSideGUID(84), 9, DetailedAmmoBoxData(8, 50)) :: InventoryItemData(ObjectClass.bullet_9mm, PlanetSideGUID(85), 12, DetailedAmmoBoxData(8, 50)) :: From a73e2f129ca8e9f1bca74ea403676d540ecb3db0 Mon Sep 17 00:00:00 2001 From: FateJH Date: Wed, 30 Aug 2017 09:35:38 -0400 Subject: [PATCH 2/5] added DetailedLockerContainerData Codec; modified PacketConverter for LockerContainer; modified tests (2) --- .../converter/LockerContainerConverter.scala | 3 ++- .../objectcreate/LockerContainerData.scala | 2 +- .../src/test/scala/objects/ConverterTest.scala | 18 ++++++++++++++++++ 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/common/src/main/scala/net/psforever/objects/definition/converter/LockerContainerConverter.scala b/common/src/main/scala/net/psforever/objects/definition/converter/LockerContainerConverter.scala index 8c578331..b01a363c 100644 --- a/common/src/main/scala/net/psforever/objects/definition/converter/LockerContainerConverter.scala +++ b/common/src/main/scala/net/psforever/objects/definition/converter/LockerContainerConverter.scala @@ -15,7 +15,8 @@ class LockerContainerConverter extends ObjectCreateConverter[LockerContainer]() } override def DetailedConstructorData(obj : LockerContainer) : Try[DetailedLockerContainerData] = { - Success(DetailedLockerContainerData(8)) + val contents : Option[List[InternalSlot]] = if(obj.Inventory.Size > 0) { Some(MakeInventory(obj.Inventory)) } else { None } + Success(DetailedLockerContainerData(8, contents)) } /** diff --git a/common/src/main/scala/net/psforever/packet/game/objectcreate/LockerContainerData.scala b/common/src/main/scala/net/psforever/packet/game/objectcreate/LockerContainerData.scala index abcc2150..3cba5574 100644 --- a/common/src/main/scala/net/psforever/packet/game/objectcreate/LockerContainerData.scala +++ b/common/src/main/scala/net/psforever/packet/game/objectcreate/LockerContainerData.scala @@ -10,7 +10,7 @@ import shapeless.{::, HNil} * A representation for a game object that can contain items.
*
* For whatever reason, these "lockers" are typically placed at the origin coordinates. - * @param inventory the items inside his locker + * @param inventory the items inside this locker */ final case class LockerContainerData(inventory : InventoryData) extends ConstructorData { override def bitsize : Long = 105L + inventory.bitsize //81u + 2u + 21u + 1u diff --git a/common/src/test/scala/objects/ConverterTest.scala b/common/src/test/scala/objects/ConverterTest.scala index 07af9365..636357e7 100644 --- a/common/src/test/scala/objects/ConverterTest.scala +++ b/common/src/test/scala/objects/ConverterTest.scala @@ -162,6 +162,24 @@ class ConverterTest extends Specification { } } + "LockerContainer" should { + "convert to packet" in { + val obj = LockerContainer() + obj.Definition.Packet.DetailedConstructorData(obj) match { + case Success(pkt) => + pkt mustEqual DetailedLockerContainerData(8) + case _ => + ko + } + obj.Definition.Packet.ConstructorData(obj) match { + case Success(pkt) => + pkt mustEqual LockerContainerData(InventoryData(List.empty)) + case _ => + ko + } + } + } + "Vehicle" should { "convert to packet" in { val hellfire_ammo = AmmoBoxDefinition(Ammo.hellfire_ammo.id) From 48e3f77d48bf1e35ac14ae578120f2aff895d00a Mon Sep 17 00:00:00 2001 From: FateJH Date: Wed, 30 Aug 2017 09:50:04 -0400 Subject: [PATCH 3/5] changing from an Option[List[_] to an Option[InventoryData] in DLockerCont to match the existing LockerContainer object and the existing LockerContainerData Codec --- .../converter/LockerContainerConverter.scala | 8 ++++-- .../DetailedLockerContainerData.scala | 26 +++++++------------ .../ObjectCreateDetailedMessageTest.scala | 2 +- 3 files changed, 17 insertions(+), 19 deletions(-) diff --git a/common/src/main/scala/net/psforever/objects/definition/converter/LockerContainerConverter.scala b/common/src/main/scala/net/psforever/objects/definition/converter/LockerContainerConverter.scala index b01a363c..c9bc0785 100644 --- a/common/src/main/scala/net/psforever/objects/definition/converter/LockerContainerConverter.scala +++ b/common/src/main/scala/net/psforever/objects/definition/converter/LockerContainerConverter.scala @@ -15,8 +15,12 @@ class LockerContainerConverter extends ObjectCreateConverter[LockerContainer]() } override def DetailedConstructorData(obj : LockerContainer) : Try[DetailedLockerContainerData] = { - val contents : Option[List[InternalSlot]] = if(obj.Inventory.Size > 0) { Some(MakeInventory(obj.Inventory)) } else { None } - Success(DetailedLockerContainerData(8, contents)) + if(obj.Inventory.Size > 0) { + Success(DetailedLockerContainerData(8, Some(InventoryData(MakeInventory(obj.Inventory))))) + } + else { + Success(DetailedLockerContainerData(8, None)) + } } /** diff --git a/common/src/main/scala/net/psforever/packet/game/objectcreate/DetailedLockerContainerData.scala b/common/src/main/scala/net/psforever/packet/game/objectcreate/DetailedLockerContainerData.scala index ef60dcb6..cae75cd8 100644 --- a/common/src/main/scala/net/psforever/packet/game/objectcreate/DetailedLockerContainerData.scala +++ b/common/src/main/scala/net/psforever/packet/game/objectcreate/DetailedLockerContainerData.scala @@ -15,20 +15,14 @@ import shapeless.{::, HNil} * Items are generally added and removed in the same way as with any other opened inventory. * Unlike other inventories, however, locker space is personal to an avatar and can not be accessed by other players. * @param unk na - * @param contents the items in the inventory + * @param inventory the items in this inventory */ final case class DetailedLockerContainerData(unk : Int, - contents : Option[List[InternalSlot]] + inventory : Option[InventoryData] ) extends ConstructorData { override def bitsize : Long = { val base : Long = 40L - var invSize : Long = 0L //length of all items in inventory - if(contents.isDefined) { - invSize = InventoryData.BaseSize - for(item <- contents.get) { - invSize += item.bitsize - } - } + val invSize : Long = if(inventory.isDefined) { inventory.get.bitsize } else { 0L } base + invSize } } @@ -45,11 +39,11 @@ object DetailedLockerContainerData extends Marshallable[DetailedLockerContainerD /** * Overloaded constructor for creating `DetailedLockerContainerData` containing known items. * @param unk na - * @param contents the items in the inventory + * @param inventory the items in the inventory * @return a `DetailedLockerContainerData` object */ - def apply(unk : Int, contents : List[InternalSlot]) : DetailedLockerContainerData = - new DetailedLockerContainerData(unk, Some(contents)) + def apply(unk : Int, inventory : List[InternalSlot]) : DetailedLockerContainerData = + new DetailedLockerContainerData(unk, Some(InventoryData(inventory))) /** * Overloaded constructor for creating `DetailedLockerContainerData` while masking use of `InternalSlot`. @@ -73,8 +67,8 @@ object DetailedLockerContainerData extends Marshallable[DetailedLockerContainerD case 0xC :: unk :: 0 :: 1 :: None :: HNil => Attempt.successful(DetailedLockerContainerData(unk, None)) - case 0xC :: unk :: 0 :: 1 :: Some(InventoryData(list)) :: HNil => - Attempt.successful(DetailedLockerContainerData(unk, Some(list))) + case 0xC :: unk :: 0 :: 1 :: Some(inv) :: HNil => + Attempt.successful(DetailedLockerContainerData(unk, Some(inv))) case _ => Attempt.failure(Err(s"invalid locker container data format")) }, @@ -82,8 +76,8 @@ object DetailedLockerContainerData extends Marshallable[DetailedLockerContainerD case DetailedLockerContainerData(unk, None) => Attempt.successful(0xC :: unk :: 0 :: 1 :: None :: HNil) - case DetailedLockerContainerData(unk, Some(list)) => - Attempt.successful(0xC :: unk :: 0 :: 1 :: Some(InventoryData(list)) :: HNil) + case DetailedLockerContainerData(unk, Some(inv)) => + Attempt.successful(0xC :: unk :: 0 :: 1 :: Some(inv) :: HNil) } ) } diff --git a/common/src/test/scala/game/ObjectCreateDetailedMessageTest.scala b/common/src/test/scala/game/ObjectCreateDetailedMessageTest.scala index 81314a8c..dfccf584 100644 --- a/common/src/test/scala/game/ObjectCreateDetailedMessageTest.scala +++ b/common/src/test/scala/game/ObjectCreateDetailedMessageTest.scala @@ -261,7 +261,7 @@ class ObjectCreateDetailedMessageTest extends Specification { inventory(3).guid mustEqual PlanetSideGUID(82) inventory(3).parentSlot mustEqual 5 inventory(3).obj.isInstanceOf[DetailedLockerContainerData] mustEqual true - inventory(3).obj.asInstanceOf[DetailedLockerContainerData].contents.isDefined mustEqual false + inventory(3).obj.asInstanceOf[DetailedLockerContainerData].inventory.isDefined mustEqual false //4 inventory(4).objectClass mustEqual ObjectClass.bullet_9mm inventory(4).guid mustEqual PlanetSideGUID(83) From 85a6eb00fd79f8c0ea658c821b6443e464a81a20 Mon Sep 17 00:00:00 2001 From: FateJH Date: Wed, 30 Aug 2017 20:20:33 -0400 Subject: [PATCH 4/5] added a LockerContainer global definition; adjusted how the lockers inhabit the fifthtSlot on players and how they are accessed; fixed converter tests to account for contents and added a quick content test; Live players will now register and unregister the contents of their fifthslot --- .../psforever/objects/GlobalDefinitions.scala | 9 ++++- .../psforever/objects/LockerContainer.scala | 8 ++--- .../scala/net/psforever/objects/Player.scala | 5 ++- .../converter/LockerContainerConverter.scala | 22 +++++++++--- .../test/scala/objects/ConverterTest.scala | 26 ++++++++++++-- .../src/main/scala/WorldSessionActor.scala | 34 +++++++++++++------ 6 files changed, 79 insertions(+), 25 deletions(-) diff --git a/common/src/main/scala/net/psforever/objects/GlobalDefinitions.scala b/common/src/main/scala/net/psforever/objects/GlobalDefinitions.scala index 34976c0c..b8666006 100644 --- a/common/src/main/scala/net/psforever/objects/GlobalDefinitions.scala +++ b/common/src/main/scala/net/psforever/objects/GlobalDefinitions.scala @@ -2,7 +2,7 @@ package net.psforever.objects import net.psforever.objects.definition._ -import net.psforever.objects.definition.converter.{CommandDetonaterConverter, REKConverter} +import net.psforever.objects.definition.converter.{CommandDetonaterConverter, LockerContainerConverter, REKConverter} import net.psforever.objects.equipment.CItem.DeployedItem import net.psforever.objects.equipment._ import net.psforever.objects.inventory.InventoryTile @@ -241,6 +241,13 @@ object GlobalDefinitions { } } + val + locker_container = new EquipmentDefinition(456) { + Name = "locker container" + Size = EquipmentSize.Inventory + Packet = new LockerContainerConverter() + } + val medkit = KitDefinition(Kits.medkit) diff --git a/common/src/main/scala/net/psforever/objects/LockerContainer.scala b/common/src/main/scala/net/psforever/objects/LockerContainer.scala index 0e535783..6c79c604 100644 --- a/common/src/main/scala/net/psforever/objects/LockerContainer.scala +++ b/common/src/main/scala/net/psforever/objects/LockerContainer.scala @@ -7,17 +7,13 @@ import net.psforever.objects.equipment.{Equipment, EquipmentSize} import net.psforever.objects.inventory.GridInventory class LockerContainer extends Equipment { - private val inventory = GridInventory() //? + private val inventory = GridInventory(30, 20) def Inventory : GridInventory = inventory def Fit(obj : Equipment) : Option[Int] = inventory.Fit(obj.Definition.Tile) - def Definition : EquipmentDefinition = new EquipmentDefinition(456) { - Name = "locker container" - Size = EquipmentSize.Inventory - Packet = new LockerContainerConverter() - } + def Definition : EquipmentDefinition = GlobalDefinitions.locker_container } object LockerContainer { diff --git a/common/src/main/scala/net/psforever/objects/Player.scala b/common/src/main/scala/net/psforever/objects/Player.scala index 85e830e7..c2300965 100644 --- a/common/src/main/scala/net/psforever/objects/Player.scala +++ b/common/src/main/scala/net/psforever/objects/Player.scala @@ -70,6 +70,7 @@ class Player(private val name : String, var PlanetsideAttribute : Array[Long] = Array.ofDim(120) Player.SuitSetup(this, ExoSuit) + fifthSlot.Equipment = new LockerContainer() //the fifth slot is the player's "locker" def Name : String = name @@ -158,7 +159,9 @@ class Player(private val name : String, holsters(slot) } else if(slot == 5) { - fifthSlot + new OffhandEquipmentSlot(EquipmentSize.Inventory) { + Equipment = fifthSlot.Equipment + } } else if(slot == Player.FreeHandSlot) { freeHand diff --git a/common/src/main/scala/net/psforever/objects/definition/converter/LockerContainerConverter.scala b/common/src/main/scala/net/psforever/objects/definition/converter/LockerContainerConverter.scala index c9bc0785..bd321313 100644 --- a/common/src/main/scala/net/psforever/objects/definition/converter/LockerContainerConverter.scala +++ b/common/src/main/scala/net/psforever/objects/definition/converter/LockerContainerConverter.scala @@ -4,7 +4,6 @@ package net.psforever.objects.definition.converter import net.psforever.objects.LockerContainer import net.psforever.objects.equipment.Equipment import net.psforever.objects.inventory.GridInventory -import net.psforever.packet.game.PlanetSideGUID import net.psforever.packet.game.objectcreate._ import scala.util.{Success, Try} @@ -16,7 +15,7 @@ class LockerContainerConverter extends ObjectCreateConverter[LockerContainer]() override def DetailedConstructorData(obj : LockerContainer) : Try[DetailedLockerContainerData] = { if(obj.Inventory.Size > 0) { - Success(DetailedLockerContainerData(8, Some(InventoryData(MakeInventory(obj.Inventory))))) + Success(DetailedLockerContainerData(8, Some(InventoryData(MakeDetailedInventory(obj.Inventory))))) } else { Success(DetailedLockerContainerData(8, None)) @@ -32,9 +31,24 @@ class LockerContainerConverter extends ObjectCreateConverter[LockerContainer]() private def MakeInventory(inv : GridInventory) : List[InternalSlot] = { inv.Items .map({ - case(guid, item) => + case(_, item) => val equip : Equipment = item.obj - InternalSlot(equip.Definition.ObjectId, PlanetSideGUID(guid), item.start, equip.Definition.Packet.ConstructorData(equip).get) + InternalSlot(equip.Definition.ObjectId, equip.GUID, item.start, equip.Definition.Packet.ConstructorData(equip).get) }).toList } + + /** + * Transform a list of contained items into a list of contained `InternalSlot` objects. + * All objects will take the form of data as if found in an `0x18` packet. + * @param inv the inventory container + * @return a list of all items that were in the inventory in decoded packet form + */ + private def MakeDetailedInventory(inv : GridInventory) : List[InternalSlot] = { + inv.Items + .map({ + case(_, item) => + val equip : Equipment = item.obj + InternalSlot(equip.Definition.ObjectId, equip.GUID, item.start, equip.Definition.Packet.DetailedConstructorData(equip).get) + }).toList + } } diff --git a/common/src/test/scala/objects/ConverterTest.scala b/common/src/test/scala/objects/ConverterTest.scala index 636357e7..2bcde21f 100644 --- a/common/src/test/scala/objects/ConverterTest.scala +++ b/common/src/test/scala/objects/ConverterTest.scala @@ -155,6 +155,7 @@ class ConverterTest extends Specification { tool.AmmoSlots.head.Box = box1 val obj = Player(PlanetSideGUID(93), "Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5) obj.Slot(2).Equipment = tool + obj.Slot(5).Equipment.get.GUID = PlanetSideGUID(94) obj.Inventory += 8 -> box2 obj.Definition.Packet.DetailedConstructorData(obj).isSuccess mustEqual true @@ -163,11 +164,11 @@ class ConverterTest extends Specification { } "LockerContainer" should { - "convert to packet" in { + "convert to packet (empty)" in { val obj = LockerContainer() obj.Definition.Packet.DetailedConstructorData(obj) match { case Success(pkt) => - pkt mustEqual DetailedLockerContainerData(8) + pkt mustEqual DetailedLockerContainerData(8, None) case _ => ko } @@ -178,6 +179,27 @@ class ConverterTest extends Specification { ko } } + + "convert to packet (occupied)" in { + import GlobalDefinitions._ + val obj = LockerContainer() + val rek = SimpleItem(remote_electronics_kit) + rek.GUID = PlanetSideGUID(1) + obj.Inventory += 0 -> rek + + obj.Definition.Packet.DetailedConstructorData(obj) match { + case Success(pkt) => + pkt mustEqual DetailedLockerContainerData(8, InternalSlot(remote_electronics_kit.ObjectId, PlanetSideGUID(1), 0, DetailedREKData(8)) :: Nil) + case _ => + ko + } + obj.Definition.Packet.ConstructorData(obj) match { + case Success(pkt) => + pkt mustEqual LockerContainerData(InventoryData(InternalSlot(remote_electronics_kit.ObjectId, PlanetSideGUID(1), 0, REKData(8,0)) :: Nil)) + case _ => + ko + } + } } "Vehicle" should { diff --git a/pslogin/src/main/scala/WorldSessionActor.scala b/pslogin/src/main/scala/WorldSessionActor.scala index 52094def..f91367a4 100644 --- a/pslogin/src/main/scala/WorldSessionActor.scala +++ b/pslogin/src/main/scala/WorldSessionActor.scala @@ -564,7 +564,7 @@ class WorldSessionActor extends Actor with MDCContextAware { forceblade1 = Tool(forceblade) forceblade1.AmmoSlots.head.Box = melee_ammo_box val rek = SimpleItem(remote_electronics_kit) - val lockerContainer = LockerContainer() + val extra_rek = SimpleItem(remote_electronics_kit) val player = Player("IlllIIIlllIlIllIlllIllI", PlanetSideEmpire.VS, CharacterGender.Female, 41, 1) player.Position = Vector3(3674.8438f, 2726.789f, 91.15625f) @@ -573,13 +573,13 @@ class WorldSessionActor extends Actor with MDCContextAware { player.Slot(0).Equipment = beamer1 player.Slot(2).Equipment = suppressor1 player.Slot(4).Equipment = forceblade1 - player.Slot(5).Equipment = lockerContainer player.Slot(6).Equipment = bullet_9mm_box1 player.Slot(9).Equipment = bullet_9mm_box2 player.Slot(12).Equipment = bullet_9mm_box3 player.Slot(33).Equipment = bullet_9mm_AP_box player.Slot(36).Equipment = energy_cell_box1 player.Slot(39).Equipment = rek + player.Slot(5).Equipment.get.asInstanceOf[LockerContainer].Inventory += 0 -> extra_rek //for player2 val energy_cell_box3 = AmmoBox(PlanetSideGUID(187), energy_cell) @@ -603,8 +603,6 @@ class WorldSessionActor extends Actor with MDCContextAware { val rek2 = SimpleItem(PlanetSideGUID(188), remote_electronics_kit) val - lockerContainer2 = LockerContainer(PlanetSideGUID(182)) - val player2 = Player(PlanetSideGUID(275), "Doppelganger", PlanetSideEmpire.NC, CharacterGender.Female, 41, 1) player2.Position = Vector3(3680f, 2726.789f, 91.15625f) player2.Orientation = Vector3(0f, 0f, 0f) @@ -612,7 +610,7 @@ class WorldSessionActor extends Actor with MDCContextAware { player2.Slot(0).Equipment = beamer2 player2.Slot(2).Equipment = suppressor2 player2.Slot(4).Equipment = forceblade2 - player2.Slot(5).Equipment = lockerContainer2 + player2.Slot(5).Equipment.get.GUID = PlanetSideGUID(182) player2.Slot(6).Equipment = bullet_9mm_box5 player2.Slot(9).Equipment = bullet_9mm_box6 player2.Slot(12).Equipment = bullet_9mm_box7 @@ -1271,8 +1269,8 @@ class WorldSessionActor extends Actor with MDCContextAware { private def RegisterAvatar(tplayer : Player) : TaskResolver.GiveTask = { val holsterTasks = recursiveHolsterTaskBuilding(tplayer.Holsters().iterator, RegisterEquipment) val fifthHolsterTask = tplayer.Slot(5).Equipment match { - case Some(item) => - RegisterEquipment(item) :: Nil + case Some(locker) => + RegisterObjectTask(locker) :: locker.asInstanceOf[LockerContainer].Inventory.Items.map({ case((_ : Int, entry : InventoryItem)) => RegisterEquipment(entry.obj)}).toList case None => List.empty[TaskResolver.GiveTask]; } @@ -1399,8 +1397,8 @@ class WorldSessionActor extends Actor with MDCContextAware { val holsterTasks = recursiveHolsterTaskBuilding(tplayer.Holsters().iterator, UnregisterEquipment) val inventoryTasks = tplayer.Inventory.Items.map({ case((_ : Int, entry : InventoryItem)) => UnregisterEquipment(entry.obj)}) val fifthHolsterTask = tplayer.Slot(5).Equipment match { - case Some(item) => - UnregisterEquipment(item) :: Nil + case Some(locker) => + UnregisterObjectTask(locker) :: locker.asInstanceOf[LockerContainer].Inventory.Items.map({ case((_ : Int, entry : InventoryItem)) => UnregisterEquipment(entry.obj)}).toList case None => List.empty[TaskResolver.GiveTask]; } @@ -1422,7 +1420,14 @@ class WorldSessionActor extends Actor with MDCContextAware { tplayer.Inventory.Items.foreach({ case((_, entry : InventoryItem)) => SetCharacterSelectScreenGUID_SelectEquipment(Some(entry.obj), gen) }) - tplayer.Slot(5).Equipment.get.GUID = PlanetSideGUID(gen.getAndIncrement) + tplayer.Slot(5).Equipment match { + case Some(locker) => + locker.GUID = PlanetSideGUID(gen.getAndIncrement) + locker.asInstanceOf[LockerContainer].Inventory.Items.foreach({ case((_, entry : InventoryItem)) => + SetCharacterSelectScreenGUID_SelectEquipment(Some(entry.obj), gen) + }) + case None => ; + } tplayer.GUID = PlanetSideGUID(gen.getAndIncrement) } @@ -1457,7 +1462,14 @@ class WorldSessionActor extends Actor with MDCContextAware { tplayer.Inventory.Items.foreach({ case((_, entry : InventoryItem)) => RemoveCharacterSelectScreenGUID_SelectEquipment(Some(entry.obj)) }) - tplayer.Slot(5).Equipment.get.Invalidate() + tplayer.Slot(5).Equipment match { + case Some(locker) => + locker.Invalidate() + locker.asInstanceOf[LockerContainer].Inventory.Items.foreach({ case((_, entry : InventoryItem)) => + RemoveCharacterSelectScreenGUID_SelectEquipment(Some(entry.obj)) + }) + case None => ; + } tplayer.Invalidate() } From 2710e3cfc9060c0c599c51edf44da2526b9d7af3 Mon Sep 17 00:00:00 2001 From: FateJH Date: Wed, 30 Aug 2017 20:25:24 -0400 Subject: [PATCH 5/5] removed excessive character initialization procedure during select screen period --- .../src/main/scala/WorldSessionActor.scala | 44 +++++++++---------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/pslogin/src/main/scala/WorldSessionActor.scala b/pslogin/src/main/scala/WorldSessionActor.scala index f91367a4..9835231e 100644 --- a/pslogin/src/main/scala/WorldSessionActor.scala +++ b/pslogin/src/main/scala/WorldSessionActor.scala @@ -1417,17 +1417,17 @@ class WorldSessionActor extends Actor with MDCContextAware { tplayer.Holsters().foreach(holster => { SetCharacterSelectScreenGUID_SelectEquipment(holster.Equipment, gen) }) - tplayer.Inventory.Items.foreach({ case((_, entry : InventoryItem)) => - SetCharacterSelectScreenGUID_SelectEquipment(Some(entry.obj), gen) - }) - tplayer.Slot(5).Equipment match { - case Some(locker) => - locker.GUID = PlanetSideGUID(gen.getAndIncrement) - locker.asInstanceOf[LockerContainer].Inventory.Items.foreach({ case((_, entry : InventoryItem)) => - SetCharacterSelectScreenGUID_SelectEquipment(Some(entry.obj), gen) - }) - case None => ; - } +// tplayer.Inventory.Items.foreach({ case((_, entry : InventoryItem)) => +// SetCharacterSelectScreenGUID_SelectEquipment(Some(entry.obj), gen) +// }) +// tplayer.Slot(5).Equipment match { +// case Some(locker) => +// locker.GUID = PlanetSideGUID(gen.getAndIncrement) +// locker.asInstanceOf[LockerContainer].Inventory.Items.foreach({ case((_, entry : InventoryItem)) => +// SetCharacterSelectScreenGUID_SelectEquipment(Some(entry.obj), gen) +// }) +// case None => ; +// } tplayer.GUID = PlanetSideGUID(gen.getAndIncrement) } @@ -1459,17 +1459,17 @@ class WorldSessionActor extends Actor with MDCContextAware { tplayer.Holsters().foreach(holster => { RemoveCharacterSelectScreenGUID_SelectEquipment(holster.Equipment) }) - tplayer.Inventory.Items.foreach({ case((_, entry : InventoryItem)) => - RemoveCharacterSelectScreenGUID_SelectEquipment(Some(entry.obj)) - }) - tplayer.Slot(5).Equipment match { - case Some(locker) => - locker.Invalidate() - locker.asInstanceOf[LockerContainer].Inventory.Items.foreach({ case((_, entry : InventoryItem)) => - RemoveCharacterSelectScreenGUID_SelectEquipment(Some(entry.obj)) - }) - case None => ; - } +// tplayer.Inventory.Items.foreach({ case((_, entry : InventoryItem)) => +// RemoveCharacterSelectScreenGUID_SelectEquipment(Some(entry.obj)) +// }) +// tplayer.Slot(5).Equipment match { +// case Some(locker) => +// locker.Invalidate() +// locker.asInstanceOf[LockerContainer].Inventory.Items.foreach({ case((_, entry : InventoryItem)) => +// RemoveCharacterSelectScreenGUID_SelectEquipment(Some(entry.obj)) +// }) +// case None => ; +// } tplayer.Invalidate() }