Packet: ZonePopulationUpdateMessage (#65)

* added ZonePopulationUpdateMessage packet and tests

* updated parameters and comments based on IDA feedback and better testing
This commit is contained in:
Fate-JH 2016-08-26 23:49:51 -04:00 committed by pschord
parent b417ef081f
commit daa22c572e
4 changed files with 102 additions and 1 deletions

View file

@ -534,7 +534,7 @@ object GamePacketOpcode extends Enumeration {
case 0xb3 => noDecoder(BattleplanMessage)
case 0xb4 => noDecoder(BattleExperienceMessage)
case 0xb5 => noDecoder(TargetingImplantRequest)
case 0xb6 => noDecoder(ZonePopulationUpdateMessage)
case 0xb6 => game.ZonePopulationUpdateMessage.decode
case 0xb7 => noDecoder(DisconnectMessage)
// 0xb8
case 0xb8 => noDecoder(ExperienceAddedMessage)

View file

@ -0,0 +1,71 @@
// Copyright (c) 2016 PSForever.net to present
package net.psforever.packet.game
import net.psforever.packet.{GamePacketOpcode, Marshallable, PlanetSideGamePacket}
import scodec.Codec
import scodec.codecs._
/**
* Report the raw numerical population for a zone (continent).<br>
* <br>
* Populations are displayed as percentages of the three main empires against each other.
* Populations specific to a zone will be displayed in the Incentives window for that zone.
* Populations in all zones will contribute to the Global Population window and the Incentives window for the server.
* The Black OPs population does not show up in the Incentives window for a zone but will be indirectly represented in the other two windows.
* This packet also shifts the flavor text for that zone.<br>
* <br>
* The size of zone's queue is the final upper population limit for that zone.
* Common values for the zone queue fields are 00 00 00 00 (locked) and 9E 01 00 00 (414 positions).
* When a continent can not accept any players at all, a lock icon will appear over its view pane in the Interstellar View.
* Setting the zone's queue to zero will also render this icon.<br>
* <br>
* The individual queue fields set the maximum empire occupancy for a zone that is represented in the zone Incentives text.
* Common values for the empire queue fields are 00 00 00 00 (locked population), 8A 00 00 00 (138 positions), and FA 01 00 00 (500 positions).
* Zone Incentives text, however, will never report more than a "100+" vacancy.
* The actual limits are probably set based on server load.
* The latter queue value is typical for VR area zones.<br>
* <br>
* The value of the zone queue trumps the sum of all individual empire queues.
* Regardless of individual queues, once total zone population matches the zone queue size, all populations will lock.
* For normal zones, if the individual queues are not set properly, whole empires can even be locked out of a zone for this reason.
* In the worst case, other empires are allowed enough individual queue vacancy that they can occupy all the available slots.
* Sanctuary zones possess strange queue values that are occasionally zero'd.
* They do not have a lock icon and may not limit populations the same way as normal zones.
*
* @param continent_guid identifies the zone (continent)
* @param zone_queue the maximum population of all three (four) empires that can join this zone
* @param tr_queue the maximum number of TR players that can join this zone
* @param tr_pop the current TR population in this zone
* @param nc_queue the maximum number of NC players that can join this zone
* @param nc_pop the current NC population in this zone
* @param vs_queue the maximum number of VS players that can join this zone
* @param vs_pop the VS population in this zone
* @param bo_queue the maximum number of Black OPs players that can join this zone
* @param bo_pop the current Black OPs population in this zone
*/
final case class ZonePopulationUpdateMessage(continent_guid : PlanetSideGUID,
zone_queue : Long,
tr_queue : Long,
tr_pop : Long,
nc_queue : Long,
nc_pop : Long,
vs_queue : Long,
vs_pop : Long,
bo_queue : Long,
bo_pop : Long)
extends PlanetSideGamePacket {
type Packet = ZonePopulationUpdateMessage
def opcode = GamePacketOpcode.ZonePopulationUpdateMessage
def encode = ZonePopulationUpdateMessage.encode(this)
}
object ZonePopulationUpdateMessage extends Marshallable[ZonePopulationUpdateMessage] {
implicit val codec : Codec[ZonePopulationUpdateMessage] = (
("continent_guid" | PlanetSideGUID.codec) ::
("zone_queue" | ulongL(32)) ::
("tr_queue" | ulongL(32)) :: ("tr_pop" | ulongL(32)) ::
("nc_queue" | ulongL(32)) :: ("nc_pop" | ulongL(32)) ::
("vs_queue" | ulongL(32)) :: ("vs_pop" | ulongL(32)) ::
("bo_queue" | ulongL(32)) :: ("bo_pop" | ulongL(32))
).as[ZonePopulationUpdateMessage]
}

View file

@ -703,6 +703,35 @@ class GamePacketTest extends Specification {
}
}
"ZonePopulationUpdateMessage" should {
val string = hex"B6 0400 9E010000 8A000000 25000000 8A000000 25000000 8A000000 25000000 8A000000 25000000"
"decode" in {
PacketCoding.DecodePacket(string).require match {
case ZonePopulationUpdateMessage(continent_guid, zone_queue, tr_queue, tr_pop, nc_queue, nc_pop, vs_queue, vs_pop, bo_queue, bo_pop) =>
continent_guid mustEqual PlanetSideGUID(4)
zone_queue mustEqual 414
tr_queue mustEqual 138
tr_pop mustEqual 37
nc_queue mustEqual 138
nc_pop mustEqual 37
vs_queue mustEqual 138
vs_pop mustEqual 37
bo_queue mustEqual 138
bo_pop mustEqual 37
case default =>
ko
}
}
"encode" in {
val msg = ZonePopulationUpdateMessage(PlanetSideGUID(4), 414, 138, 37, 138, 37, 138, 37, 138, 37)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string
}
}
"WeaponFireMessage" should {
val string = hex"34 44130029272F0B5DFD4D4EC5C00009BEF78172003FC0"

View file

@ -138,6 +138,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
// LoadMapMessage 13714 in mossy .gcap
// XXX: hardcoded shit
sendResponse(PacketCoding.CreateGamePacket(0, LoadMapMessage("map13","home3",40100,25,true,3770441820L))) //VS Sanctuary
sendResponse(PacketCoding.CreateGamePacket(0, ZonePopulationUpdateMessage(PlanetSideGUID(13), 414, 138, 0, 138, 0, 138, 0, 138, 0)))
sendRawResponse(objectHex)
// These object_guids are specfic to VS Sanc