Maxes and Turrets Fixes (#237)

* modified DCData to account for Max suit encoding; modified converters for the avatar that would make use of DCData changes; corrections to enforce that Max/ex-Max always has correct hand showing

* separating initialization-time random GUID assignments from initialization-time fixed GUID assignments by performing them all later
This commit is contained in:
Fate-JH 2018-11-21 20:00:33 -05:00 committed by GitHub
parent 5a67fcd88d
commit 7588166ac0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 452 additions and 28 deletions

View file

@ -4,7 +4,7 @@ package net.psforever.objects.definition.converter
import net.psforever.objects.{EquipmentSlot, Player}
import net.psforever.objects.equipment.Equipment
import net.psforever.packet.game.objectcreate._
import net.psforever.types.{GrenadeState, ImplantType}
import net.psforever.types.{ExoSuitType, GrenadeState, ImplantType}
import scala.annotation.tailrec
import scala.util.{Success, Try}
@ -124,7 +124,8 @@ object AvatarConverter {
}
def MakeDetailedCharacterData(obj : Player) : (Option[Int])=>DetailedCharacterData = {
val bep = obj.BEP
val bep : Long = obj.BEP
val maxOpt : Option[Long] = if(obj.ExoSuit == ExoSuitType.MAX) { Some(0L) } else { None }
val ba : DetailedCharacterA = DetailedCharacterA(
bep,
obj.CEP,
@ -134,6 +135,7 @@ object AvatarConverter {
obj.Armor,
0L,
obj.MaxStamina, obj.Stamina,
maxOpt,
0, 0, 0L,
List(0, 0, 0, 0, 0, 0),
obj.Certifications.toList.sortBy(_.id) //TODO is sorting necessary?

View file

@ -4,7 +4,7 @@ package net.psforever.objects.definition.converter
import net.psforever.objects.{EquipmentSlot, Player}
import net.psforever.objects.equipment.Equipment
import net.psforever.packet.game.objectcreate._
import net.psforever.types.{CertificationType, CharacterVoice, GrenadeState, ImplantType}
import net.psforever.types._
import scala.annotation.tailrec
import scala.util.{Failure, Success, Try}
@ -77,7 +77,8 @@ class CharacterSelectConverter extends AvatarConverter {
}
private def MakeDetailedCharacterData(obj : Player) : (Option[Int]=>DetailedCharacterData) = {
val bep = obj.BEP
val bep : Long = obj.BEP
val maxOpt : Option[Long] = if(obj.ExoSuit == ExoSuitType.MAX) { Some(0L) } else { None }
val ba : DetailedCharacterA = DetailedCharacterA(
bep,
obj.CEP,
@ -87,6 +88,7 @@ class CharacterSelectConverter extends AvatarConverter {
0,
0L,
1, 1,
maxOpt,
0, 0, 0L,
List(0, 0, 0, 0, 0, 0),
certs = List.empty[CertificationType.Value]

View file

@ -72,6 +72,7 @@ class CorpseConverter extends AvatarConverter {
}
private def MakeDetailedCharacterData(obj : Player) : (Option[Int]=>DetailedCharacterData) = {
val maxOpt : Option[Long] = if(obj.ExoSuit == ExoSuitType.MAX) { Some(0L) } else { None }
val ba : DetailedCharacterA = DetailedCharacterA(
bep = 0L,
cep = 0L,
@ -81,6 +82,7 @@ class CorpseConverter extends AvatarConverter {
0,
0L,
0, 0,
maxOpt,
0, 0, 0L,
List(0, 0, 0, 0, 0, 0),
certs = List.empty[CertificationType.Value]

View file

@ -6,6 +6,7 @@ import akka.routing.RandomPool
import net.psforever.objects.ballistics.Projectile
import net.psforever.objects._
import net.psforever.objects.ce.Deployable
import net.psforever.objects.entity.IdentifiableEntity
import net.psforever.objects.equipment.Equipment
import net.psforever.objects.guid.NumberPoolHub
import net.psforever.objects.guid.actor.UniqueNumberSystem
@ -313,6 +314,7 @@ class Zone(private val zoneId : String, zoneMap : ZoneMap, zoneNumber : Int) {
private def BuildSupportObjects() : Unit = {
//guard against errors here, but don't worry about specifics; let ZoneActor.ZoneSetupCheck complain about problems
val other : ListBuffer[IdentifiableEntity] = new ListBuffer[IdentifiableEntity]()
//turret to weapon
Map.TurretToWeapon.foreach({ case ((turret_guid, weapon_guid)) =>
((GUID(turret_guid) match {
@ -333,11 +335,13 @@ class Zone(private val zoneId : String, zoneMap : ZoneMap, zoneNumber : Int) {
}) match {
case Some((obj, Some(weapon : Tool))) =>
guid.register(weapon, weapon_guid)
weapon.AmmoSlots.foreach(slot => guid.register(slot.Box, "dynamic"))
obj.Inventory.Items.foreach(item => guid.register(item.obj, "dynamic")) //internal ammunition reserves, if any
other ++= weapon.AmmoSlots.map(slot => slot.Box)
other ++= obj.Inventory.Items.map(item => item.obj) //internal ammunition reserves, if any
case _ => ;
}
})
//after all fixed GUID's are defined ...
other.foreach(obj => guid.register(obj, "dynamic"))
}
private def MakeBuildings(implicit context : ActorContext) : PairMap[Int, Building] = {

View file

@ -3,7 +3,7 @@ package net.psforever.packet.game.objectcreate
import net.psforever.newcodecs.newcodecs
import net.psforever.packet.{Marshallable, PacketHelpers}
import net.psforever.types.{CertificationType, ImplantType}
import net.psforever.types.{CertificationType, ExoSuitType, ImplantType}
import scodec.{Attempt, Codec}
import scodec.codecs._
import shapeless.{::, HNil}
@ -71,6 +71,8 @@ final case class DCDExtra2(unk1 : Int,
* range is 0-65535
* @param stamina for `x / y` of stamina points, this is the avatar's `x` value;
* range is 0-65535
* @param max_field unk;
* this field exists only when the player is wearing a mechanized assault exo-suit
* @param certs the `List` of certifications
*/
final case class DetailedCharacterA(bep : Long,
@ -85,14 +87,16 @@ final case class DetailedCharacterA(bep : Long,
unk5 : Long,
staminaMax : Int,
stamina : Int,
max_field : Option[Long],
unk6 : Int,
unk7 : Int,
unk8 : Long,
unk9 : List[Int],
certs : List[CertificationType.Value]) extends StreamBitSize {
override def bitsize : Long = {
val maxFieldSize = max_field match { case Some(_) => 32L ; case None => 0L }
val certSize : Long = certs.length * 8
428L + certSize
428L + maxFieldSize + certSize
}
}
@ -197,6 +201,7 @@ object DetailedCharacterData extends Marshallable[DetailedCharacterData] {
armor : Int,
staminaMax : Int,
stamina : Int,
maxField : Option[Long],
certs : List[CertificationType.Value],
implants : List[ImplantEntry],
firstTimeEvents : List[String],
@ -213,6 +218,7 @@ object DetailedCharacterData extends Marshallable[DetailedCharacterData] {
armor,
0L,
staminaMax, stamina,
maxField,
0,
0,
0L,
@ -527,7 +533,7 @@ object DetailedCharacterData extends Marshallable[DetailedCharacterData] {
*/
def isBR24(bep : Long) : Boolean = bep > 2286230
val a_codec : Codec[DetailedCharacterA] = (
def a_codec(suit : ExoSuitType.Value) : Codec[DetailedCharacterA] = (
("bep" | uint32L) ::
("cep" | uint32L) ::
("unk1" | uint32L) ::
@ -540,7 +546,7 @@ object DetailedCharacterData extends Marshallable[DetailedCharacterData] {
("unk5" | uint32) :: //endianness?
("staminaMax" | uint16L) ::
("stamina" | uint16L) ::
conditional(false, uint32L) :: //see ps.c: sub_901150, line#1070692
conditional(suit == ExoSuitType.MAX, uint32L) ::
("unk6" | uint16L) ::
("unk7" | uint(3)) ::
("unk8" | uint32L) ::
@ -548,13 +554,13 @@ object DetailedCharacterData extends Marshallable[DetailedCharacterData] {
("certs" | listOfN(uint8L, CertificationType.codec))
).exmap[DetailedCharacterA] (
{
case bep :: cep :: u1 :: u2 :: u3 :: healthMax :: health :: u4 :: armor :: u5 :: staminaMax :: stamina :: None :: u6 :: u7 :: u8 :: u9 :: certs :: HNil =>
Attempt.successful(DetailedCharacterA(bep, cep, u1, u2, u3, healthMax, health, u4, armor, u5, staminaMax, stamina, u6, u7, u8, u9, certs))
case bep :: cep :: u1 :: u2 :: u3 :: healthMax :: health :: u4 :: armor :: u5 :: staminaMax :: stamina :: max :: u6 :: u7 :: u8 :: u9 :: certs :: HNil =>
Attempt.successful(DetailedCharacterA(bep, cep, u1, u2, u3, healthMax, health, u4, armor, u5, staminaMax, stamina, max, u6, u7, u8, u9, certs))
},
{
case DetailedCharacterA(bep, cep, u1, u2, u3, healthMax, health, u4, armor, u5, staminaMax, stamina, u6, u7, u8, u9, certs) =>
case DetailedCharacterA(bep, cep, u1, u2, u3, healthMax, health, u4, armor, u5, staminaMax, stamina, max, u6, u7, u8, u9, certs) =>
Attempt.successful(
bep :: cep :: u1 :: u2 :: u3 :: healthMax :: health :: u4 :: armor :: u5 :: staminaMax :: stamina :: None :: u6 :: u7 :: u8 :: u9 :: certs :: HNil
bep :: cep :: u1 :: u2 :: u3 :: healthMax :: health :: u4 :: armor :: u5 :: staminaMax :: stamina :: max :: u6 :: u7 :: u8 :: u9 :: certs :: HNil
)
}
)
@ -614,8 +620,8 @@ object DetailedCharacterData extends Marshallable[DetailedCharacterData] {
}
)
def codec(pad_length : Option[Int]) : Codec[DetailedCharacterData] = (
("a" | a_codec) >>:~ { a =>
def codec(suit : ExoSuitType.Value, pad_length : Option[Int]) : Codec[DetailedCharacterData] = (
("a" | a_codec(suit)) >>:~ { a =>
("b" | b_codec(a.bep, pad_length)).hlist
}
).exmap[DetailedCharacterData] (
@ -629,5 +635,5 @@ object DetailedCharacterData extends Marshallable[DetailedCharacterData] {
}
)
implicit val codec : Codec[DetailedCharacterData] = codec(None)
implicit val codec : Codec[DetailedCharacterData] = codec(ExoSuitType.Standard, None)
}

View file

@ -114,7 +114,7 @@ object DetailedPlayerData extends Marshallable[DetailedPlayerData] {
def codec(position_defined : Boolean) : Codec[DetailedPlayerData] = (
conditional(position_defined, "pos" | PlacementData.codec) >>:~ { pos =>
("basic_appearance" | CharacterAppearanceData.codec(PlayerData.PaddingOffset(pos))) >>:~ { app =>
("character_data" | DetailedCharacterData.codec(app.altModelBit)) ::
("character_data" | DetailedCharacterData.codec(app.a.exosuit, app.altModelBit)) ::
optional(bool, "inventory" | InventoryData.codec_detailed) ::
("drawn_slot" | DrawnSlot.codec) ::
bool //usually false

File diff suppressed because one or more lines are too long

View file

@ -1460,17 +1460,17 @@ class WorldSessionActor extends Actor with MDCContextAware {
}
else {
//remove potential MAX weapon
tplayer.DrawnSlot = Player.HandsDownSlot
sendResponse(ObjectHeldMessage(tplayer.GUID, Player.HandsDownSlot, true))
val normalWeapons = if(originalSuit == ExoSuitType.MAX) {
val (maxWeapons, normalWeapons) = beforeHolsters.partition(elem => elem.obj.Size == EquipmentSize.Max)
maxWeapons.foreach(entry => {
taskResolver ! GUIDTask.UnregisterEquipment(entry.obj)(continent.GUID)
})
avatarService ! AvatarServiceMessage(player.Continent, AvatarAction.ObjectHeld(player.GUID, player.LastDrawnSlot))
normalWeapons
}
else {
tplayer.DrawnSlot = Player.HandsDownSlot
sendResponse(ObjectHeldMessage(tplayer.GUID, Player.HandsDownSlot, true))
avatarService ! AvatarServiceMessage(tplayer.Continent, AvatarAction.ObjectHeld(tplayer.GUID, Player.HandsDownSlot))
beforeHolsters
}
//fill holsters
@ -2879,7 +2879,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
//we're driving the vehicle
player.Position = pos //convenient
if(seat.ControlledWeapon.isEmpty) {
player.Orientation = Vector3(0f, 0f, ang.z) //convenient
player.Orientation = Vector3.z(ang.z) //convenient
}
obj.Position = pos
obj.Orientation = ang

View file

@ -476,6 +476,7 @@ class PacketCodingActorITest extends ActorTest {
100, 100,
50,
100, 100,
None,
List(CertificationType.StandardAssault, CertificationType.MediumAssault, CertificationType.ATV, CertificationType.Harasser, CertificationType.StandardExoSuit, CertificationType.AgileExoSuit, CertificationType.ReinforcedExoSuit),
List(),
List(),
@ -601,6 +602,7 @@ class PacketCodingActorKTest extends ActorTest {
50,
32831L,
100, 100,
None,
0, 0, 0L,
List(0, 0, 0, 0, 0, 0),
List(