Fix variable naming

Added comments
Added enums for ease of use
Typed packet variables
Added 3 more samples to test cases
This commit is contained in:
Resaec 2025-12-17 03:53:50 +01:00
parent 3c074bbd70
commit 6551de6f53
2 changed files with 228 additions and 33 deletions

View file

@ -1,14 +1,25 @@
// Copyright (c) 2025 PSForever
package net.psforever.packet.game
import net.psforever.packet.game.EmpireBenefitsMessage.{ZoneLocks, ZoneBenefits}
import net.psforever.packet.game.EmpireBenefitsMessage.{ZoneBenefit, ZoneLock}
import net.psforever.packet.{GamePacketOpcode, Marshallable, PacketHelpers, PlanetSideGamePacket}
import net.psforever.types.PlanetSideEmpire
import scodec.Codec
import scodec.codecs._
import scala.language.implicitConversions
/**
* EmpireBenefitsMessage
*
* zoneLocks gives the client information about which empire locks what continent.
* This produces a chat message.
* zoneBenefits tells the client what empire has which benefits enabled.
* This has to match zoneLocks to work properly.
*/
final case class EmpireBenefitsMessage(
entriesA: Vector[ZoneLocks],
entriesB: Vector[ZoneBenefits]
zoneLocks: Vector[ZoneLock],
zoneBenefits: Vector[ZoneBenefit]
) extends PlanetSideGamePacket {
type Packet = EmpireBenefitsMessage
def opcode = GamePacketOpcode.EmpireBenefitsMessage
@ -17,28 +28,83 @@ final case class EmpireBenefitsMessage(
object EmpireBenefitsMessage extends Marshallable[EmpireBenefitsMessage] {
final case class ZoneLocks(
empire: Int,
zone: String
/**
* ZoneLockZone
*
* Available Types of Zones
*
* These zones can be used to notify the client of a lock.
*/
object ZoneLockZone extends Enumeration {
type Type = String
val i1: ZoneLockZone.Value = Value("lock-i1") // Extinction Continental Lock
val i2: ZoneLockZone.Value = Value("lock-i2") // Ascension Continental Lock
val i3: ZoneLockZone.Value = Value("lock-i3") // Desolation Continental Lock
val i4: ZoneLockZone.Value = Value("lock-i4") // Nexus Continental Lock
val i1_i2_i3_i4: ZoneLockZone.Value = Value("lock-i1-i2-i3-i4") // Oshur Cluster Lock
val z3: ZoneLockZone.Value = Value("lock-z3") // Cyssor Continental Lock
val z4: ZoneLockZone.Value = Value("lock-z4") // Ishundar Continental Lock
val z9: ZoneLockZone.Value = Value("lock-z9") // Searhus Continental Lock
val tr_homes: ZoneLockZone.Value = Value("lock-tr-homes") // TR Home Continent Lock
val nc_homes: ZoneLockZone.Value = Value("lock-nc-homes") // NC Home Continent Lock
val vs_homes: ZoneLockZone.Value = Value("lock-vs-homes") // VS Home Continent Lock
implicit def valueToType(v: ZoneLockZone.Value): Type = v.toString
implicit val codec: Codec[Type] = PacketHelpers.encodedStringAligned(6)
}
/**
* ZoneLockBenefit
*
* Available Types of Benefits
*
* Benefits 0, 2 and 5 are unknown. Benefits for i1 to i4 are unknown and mapped incorrectly here.
*/
object ZoneLockBenefit extends Enumeration {
type Type = Value
val i1: ZoneLockBenefit.Value = Value(-1) // Extinction Continental Lock
val i2: ZoneLockBenefit.Value = Value(-2) // Ascension Continental Lock
val i3: ZoneLockBenefit.Value = Value(-3) // Desolation Continental Lock
val i4: ZoneLockBenefit.Value = Value(-4) // Nexus Continental Lock
// val unk0: ZoneLockBenefit.Value = Value(0)
val z4: ZoneLockBenefit.Value = Value(1) // Ishundar Continental Lock
// val unk2: ZoneLockBenefit.Value = Value(2)
val z9: ZoneLockBenefit.Value = Value(3) // Searhus Continental Lock
val i1_i2_i3_i4: ZoneLockBenefit.Value = Value(4) // Oshur Cluster Lock
// val unk5: ZoneLockBenefit.Value = Value(5)
val z3: ZoneLockBenefit.Value = Value(6) // Cyssor Continental Lock
val tr_homes: ZoneLockBenefit.Value = Value(7) // TR Home Continent Lock
val nc_homes: ZoneLockBenefit.Value = Value(8) // NC Home Continent Lock
val vs_homes: ZoneLockBenefit.Value = Value(9) // VS Home Continent Lock
implicit val codec: Codec[Type] = PacketHelpers.createEnumerationCodec(this, uint16L)
}
final case class ZoneLock(
empire: PlanetSideEmpire.Type,
zone: ZoneLockZone.Type,
)
final case class ZoneBenefits(
empire: Int,
value: Int
final case class ZoneBenefit(
empire: PlanetSideEmpire.Type,
value: ZoneLockBenefit.Type
)
private implicit val entryACodec: Codec[ZoneLocks] = (
("empire" | uint(2)) ::
("zone" | PacketHelpers.encodedStringAligned(6))
).as[ZoneLocks]
private implicit val zoneLockCodec: Codec[ZoneLock] = (
("empire" | PlanetSideEmpire.codec) ::
("zone" | ZoneLockZone.codec)
).as[ZoneLock]
private implicit val entryBCodec: Codec[ZoneBenefits] = (
("empire" | uint(2)) ::
("benefit" | uint16L)
).as[ZoneBenefits]
private implicit val zoneBenefitCodec: Codec[ZoneBenefit] = (
("empire" | PlanetSideEmpire.codec) ::
("benefit" | ZoneLockBenefit.codec)
).as[ZoneBenefit]
implicit val codec: Codec[EmpireBenefitsMessage] = (
("entriesA" | vectorOfN(uint32L.xmap(_.toInt, _.toLong), entryACodec)) ::
("entriesB" | vectorOfN(uint32L.xmap(_.toInt, _.toLong), entryBCodec))
("zoneLocks" | vectorOfN(uint32L.xmap(_.toInt, _.toLong), zoneLockCodec)) ::
("zoneBenefits" | vectorOfN(uint32L.xmap(_.toInt, _.toLong), zoneBenefitCodec))
).as[EmpireBenefitsMessage]
}

View file

@ -2,8 +2,9 @@
package game
import net.psforever.packet._
import net.psforever.packet.game.EmpireBenefitsMessage.{ZoneLocks, ZoneBenefits}
import net.psforever.packet.game.{EmpireBenefitsMessage, OutfitEvent}
import net.psforever.packet.game.EmpireBenefitsMessage
import net.psforever.packet.game.EmpireBenefitsMessage.{ZoneBenefit, ZoneLock, ZoneLockBenefit, ZoneLockZone}
import net.psforever.types.PlanetSideEmpire
import org.specs2.mutable._
import scodec.bits._
@ -17,18 +18,86 @@ class EmpireBenefitsMessageTest extends Specification {
"004000600410020300"
)
val sample1_expectedLocks = Vector(
ZoneLocks(0, "lock-z3"),
ZoneLocks(0, "lock-z4"),
ZoneLocks(1, "lock-i1-i2-i3-i4"),
ZoneLocks(2, "lock-z9")
val sample2: ByteVector = ByteVector.fromValidHex(
"d7" +
"05000000 23406c6f636b2d76732d686f6d657321c06c6f636b2d7a3321c06c6f636b2d7a3461c06c6f636b2d7a3964006c6f636b2d69312d69322d69332d6934" +
"05000000 004000600024010300410000"
)
val sample1_expectedBenefits = Vector(
ZoneBenefits(0, 1),
ZoneBenefits(0, 6),
ZoneBenefits(1, 4),
ZoneBenefits(2, 3)
val sample3: ByteVector = ByteVector.fromValidHex(
"d7" +
"05000000 21c06c6f636b2d7a3321c06c6f636b2d7a3423406c6f636b2d6e632d686f6d657361c06c6f636b2d7a39a4006c6f636b2d69312d69322d69332d6934" +
"05000000 004000600020010300810000"
)
val sample4: ByteVector = ByteVector.fromValidHex(
"d7" +
"06000000 a3406c6f636b2d6e632d686f6d6573a3406c6f636b2d74722d686f6d6573a1c06c6f636b2d7a33a1c06c6f636b2d7a34a1c06c6f636b2d7a39a4006c6f636b2d69312d69322d69332d6934" +
"06000000 80402030081002060081c0208000"
)
private val sample1_expectedLocks = Vector(
ZoneLock(PlanetSideEmpire.TR, ZoneLockZone.z3),
ZoneLock(PlanetSideEmpire.TR, ZoneLockZone.z4),
ZoneLock(PlanetSideEmpire.NC, ZoneLockZone.i1_i2_i3_i4),
ZoneLock(PlanetSideEmpire.VS, ZoneLockZone.z9)
)
private val sample1_expectedBenefits = Vector(
ZoneBenefit(PlanetSideEmpire.TR, ZoneLockBenefit.z4),
ZoneBenefit(PlanetSideEmpire.TR, ZoneLockBenefit.z3),
ZoneBenefit(PlanetSideEmpire.NC, ZoneLockBenefit.i1_i2_i3_i4),
ZoneBenefit(PlanetSideEmpire.VS, ZoneLockBenefit.z9)
)
private val sample2_expectedLocks = Vector(
ZoneLock(PlanetSideEmpire.TR, ZoneLockZone.vs_homes),
ZoneLock(PlanetSideEmpire.TR, ZoneLockZone.z3),
ZoneLock(PlanetSideEmpire.TR, ZoneLockZone.z4),
ZoneLock(PlanetSideEmpire.NC, ZoneLockZone.z9),
ZoneLock(PlanetSideEmpire.NC, ZoneLockZone.i1_i2_i3_i4)
)
private val sample2_expectedBenefits = Vector(
ZoneBenefit(PlanetSideEmpire.TR, ZoneLockBenefit.z4),
ZoneBenefit(PlanetSideEmpire.TR, ZoneLockBenefit.z3),
ZoneBenefit(PlanetSideEmpire.TR, ZoneLockBenefit.vs_homes),
ZoneBenefit(PlanetSideEmpire.NC, ZoneLockBenefit.z9),
ZoneBenefit(PlanetSideEmpire.NC, ZoneLockBenefit.i1_i2_i3_i4)
)
private val sample3_expectedLocks = Vector(
ZoneLock(PlanetSideEmpire.TR, ZoneLockZone.z3),
ZoneLock(PlanetSideEmpire.TR, ZoneLockZone.z4),
ZoneLock(PlanetSideEmpire.TR, ZoneLockZone.nc_homes),
ZoneLock(PlanetSideEmpire.NC, ZoneLockZone.z9),
ZoneLock(PlanetSideEmpire.VS, ZoneLockZone.i1_i2_i3_i4)
)
private val sample3_expectedBenefits = Vector(
ZoneBenefit(PlanetSideEmpire.TR, ZoneLockBenefit.z4),
ZoneBenefit(PlanetSideEmpire.TR, ZoneLockBenefit.z3),
ZoneBenefit(PlanetSideEmpire.TR, ZoneLockBenefit.nc_homes),
ZoneBenefit(PlanetSideEmpire.NC, ZoneLockBenefit.z9),
ZoneBenefit(PlanetSideEmpire.VS, ZoneLockBenefit.i1_i2_i3_i4)
)
private val sample4_expectedLocks = Vector(
ZoneLock(PlanetSideEmpire.VS, ZoneLockZone.nc_homes),
ZoneLock(PlanetSideEmpire.VS, ZoneLockZone.tr_homes),
ZoneLock(PlanetSideEmpire.VS, ZoneLockZone.z3),
ZoneLock(PlanetSideEmpire.VS, ZoneLockZone.z4),
ZoneLock(PlanetSideEmpire.VS, ZoneLockZone.z9),
ZoneLock(PlanetSideEmpire.VS, ZoneLockZone.i1_i2_i3_i4)
)
private val sample4_expectedBenefits = Vector(
ZoneBenefit(PlanetSideEmpire.VS, ZoneLockBenefit.z4),
ZoneBenefit(PlanetSideEmpire.VS, ZoneLockBenefit.z9),
ZoneBenefit(PlanetSideEmpire.VS, ZoneLockBenefit.i1_i2_i3_i4),
ZoneBenefit(PlanetSideEmpire.VS, ZoneLockBenefit.z3),
ZoneBenefit(PlanetSideEmpire.VS, ZoneLockBenefit.tr_homes),
ZoneBenefit(PlanetSideEmpire.VS, ZoneLockBenefit.nc_homes)
)
"decode sample1" in {
@ -43,11 +112,71 @@ class EmpireBenefitsMessageTest extends Specification {
"encode sample1" in {
val msg = EmpireBenefitsMessage(
entriesA = sample1_expectedLocks,
entriesB = sample1_expectedBenefits
zoneLocks = sample1_expectedLocks,
zoneBenefits = sample1_expectedBenefits
)
val pkt = PacketCoding.encodePacket(msg).require.toByteVector
pkt mustEqual sample1
}
"decode sample2" in {
PacketCoding.decodePacket(sample2).require match {
case EmpireBenefitsMessage(a, b) =>
a mustEqual sample2_expectedLocks
b mustEqual sample2_expectedBenefits
case _ =>
ko
}
}
"encode sample2" in {
val msg = EmpireBenefitsMessage(
zoneLocks = sample2_expectedLocks,
zoneBenefits = sample2_expectedBenefits
)
val pkt = PacketCoding.encodePacket(msg).require.toByteVector
pkt mustEqual sample2
}
"decode sample3" in {
PacketCoding.decodePacket(sample3).require match {
case EmpireBenefitsMessage(a, b) =>
a mustEqual sample3_expectedLocks
b mustEqual sample3_expectedBenefits
case _ =>
ko
}
}
"encode sample3" in {
val msg = EmpireBenefitsMessage(
zoneLocks = sample3_expectedLocks,
zoneBenefits = sample3_expectedBenefits
)
val pkt = PacketCoding.encodePacket(msg).require.toByteVector
pkt mustEqual sample3
}
"decode sample4" in {
PacketCoding.decodePacket(sample4).require match {
case EmpireBenefitsMessage(a, b) =>
a mustEqual sample4_expectedLocks
b mustEqual sample4_expectedBenefits
case _ =>
ko
}
}
"encode sample4" in {
val msg = EmpireBenefitsMessage(
zoneLocks = sample4_expectedLocks,
zoneBenefits = sample4_expectedBenefits
)
val pkt = PacketCoding.encodePacket(msg).require.toByteVector
pkt mustEqual sample4
}
}