mirror of
https://github.com/2revoemag/PSF-BotServer.git
synced 2026-07-12 15:04:39 +00:00
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:
parent
5a67fcd88d
commit
7588166ac0
9 changed files with 452 additions and 28 deletions
|
|
@ -4,7 +4,7 @@ package net.psforever.objects.definition.converter
|
||||||
import net.psforever.objects.{EquipmentSlot, Player}
|
import net.psforever.objects.{EquipmentSlot, Player}
|
||||||
import net.psforever.objects.equipment.Equipment
|
import net.psforever.objects.equipment.Equipment
|
||||||
import net.psforever.packet.game.objectcreate._
|
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.annotation.tailrec
|
||||||
import scala.util.{Success, Try}
|
import scala.util.{Success, Try}
|
||||||
|
|
@ -124,7 +124,8 @@ object AvatarConverter {
|
||||||
}
|
}
|
||||||
|
|
||||||
def MakeDetailedCharacterData(obj : Player) : (Option[Int])=>DetailedCharacterData = {
|
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(
|
val ba : DetailedCharacterA = DetailedCharacterA(
|
||||||
bep,
|
bep,
|
||||||
obj.CEP,
|
obj.CEP,
|
||||||
|
|
@ -134,6 +135,7 @@ object AvatarConverter {
|
||||||
obj.Armor,
|
obj.Armor,
|
||||||
0L,
|
0L,
|
||||||
obj.MaxStamina, obj.Stamina,
|
obj.MaxStamina, obj.Stamina,
|
||||||
|
maxOpt,
|
||||||
0, 0, 0L,
|
0, 0, 0L,
|
||||||
List(0, 0, 0, 0, 0, 0),
|
List(0, 0, 0, 0, 0, 0),
|
||||||
obj.Certifications.toList.sortBy(_.id) //TODO is sorting necessary?
|
obj.Certifications.toList.sortBy(_.id) //TODO is sorting necessary?
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ package net.psforever.objects.definition.converter
|
||||||
import net.psforever.objects.{EquipmentSlot, Player}
|
import net.psforever.objects.{EquipmentSlot, Player}
|
||||||
import net.psforever.objects.equipment.Equipment
|
import net.psforever.objects.equipment.Equipment
|
||||||
import net.psforever.packet.game.objectcreate._
|
import net.psforever.packet.game.objectcreate._
|
||||||
import net.psforever.types.{CertificationType, CharacterVoice, GrenadeState, ImplantType}
|
import net.psforever.types._
|
||||||
|
|
||||||
import scala.annotation.tailrec
|
import scala.annotation.tailrec
|
||||||
import scala.util.{Failure, Success, Try}
|
import scala.util.{Failure, Success, Try}
|
||||||
|
|
@ -77,7 +77,8 @@ class CharacterSelectConverter extends AvatarConverter {
|
||||||
}
|
}
|
||||||
|
|
||||||
private def MakeDetailedCharacterData(obj : Player) : (Option[Int]=>DetailedCharacterData) = {
|
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(
|
val ba : DetailedCharacterA = DetailedCharacterA(
|
||||||
bep,
|
bep,
|
||||||
obj.CEP,
|
obj.CEP,
|
||||||
|
|
@ -87,6 +88,7 @@ class CharacterSelectConverter extends AvatarConverter {
|
||||||
0,
|
0,
|
||||||
0L,
|
0L,
|
||||||
1, 1,
|
1, 1,
|
||||||
|
maxOpt,
|
||||||
0, 0, 0L,
|
0, 0, 0L,
|
||||||
List(0, 0, 0, 0, 0, 0),
|
List(0, 0, 0, 0, 0, 0),
|
||||||
certs = List.empty[CertificationType.Value]
|
certs = List.empty[CertificationType.Value]
|
||||||
|
|
|
||||||
|
|
@ -72,6 +72,7 @@ class CorpseConverter extends AvatarConverter {
|
||||||
}
|
}
|
||||||
|
|
||||||
private def MakeDetailedCharacterData(obj : Player) : (Option[Int]=>DetailedCharacterData) = {
|
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(
|
val ba : DetailedCharacterA = DetailedCharacterA(
|
||||||
bep = 0L,
|
bep = 0L,
|
||||||
cep = 0L,
|
cep = 0L,
|
||||||
|
|
@ -81,6 +82,7 @@ class CorpseConverter extends AvatarConverter {
|
||||||
0,
|
0,
|
||||||
0L,
|
0L,
|
||||||
0, 0,
|
0, 0,
|
||||||
|
maxOpt,
|
||||||
0, 0, 0L,
|
0, 0, 0L,
|
||||||
List(0, 0, 0, 0, 0, 0),
|
List(0, 0, 0, 0, 0, 0),
|
||||||
certs = List.empty[CertificationType.Value]
|
certs = List.empty[CertificationType.Value]
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ import akka.routing.RandomPool
|
||||||
import net.psforever.objects.ballistics.Projectile
|
import net.psforever.objects.ballistics.Projectile
|
||||||
import net.psforever.objects._
|
import net.psforever.objects._
|
||||||
import net.psforever.objects.ce.Deployable
|
import net.psforever.objects.ce.Deployable
|
||||||
|
import net.psforever.objects.entity.IdentifiableEntity
|
||||||
import net.psforever.objects.equipment.Equipment
|
import net.psforever.objects.equipment.Equipment
|
||||||
import net.psforever.objects.guid.NumberPoolHub
|
import net.psforever.objects.guid.NumberPoolHub
|
||||||
import net.psforever.objects.guid.actor.UniqueNumberSystem
|
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 = {
|
private def BuildSupportObjects() : Unit = {
|
||||||
//guard against errors here, but don't worry about specifics; let ZoneActor.ZoneSetupCheck complain about problems
|
//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
|
//turret to weapon
|
||||||
Map.TurretToWeapon.foreach({ case ((turret_guid, weapon_guid)) =>
|
Map.TurretToWeapon.foreach({ case ((turret_guid, weapon_guid)) =>
|
||||||
((GUID(turret_guid) match {
|
((GUID(turret_guid) match {
|
||||||
|
|
@ -333,11 +335,13 @@ class Zone(private val zoneId : String, zoneMap : ZoneMap, zoneNumber : Int) {
|
||||||
}) match {
|
}) match {
|
||||||
case Some((obj, Some(weapon : Tool))) =>
|
case Some((obj, Some(weapon : Tool))) =>
|
||||||
guid.register(weapon, weapon_guid)
|
guid.register(weapon, weapon_guid)
|
||||||
weapon.AmmoSlots.foreach(slot => guid.register(slot.Box, "dynamic"))
|
other ++= weapon.AmmoSlots.map(slot => slot.Box)
|
||||||
obj.Inventory.Items.foreach(item => guid.register(item.obj, "dynamic")) //internal ammunition reserves, if any
|
other ++= obj.Inventory.Items.map(item => item.obj) //internal ammunition reserves, if any
|
||||||
case _ => ;
|
case _ => ;
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
//after all fixed GUID's are defined ...
|
||||||
|
other.foreach(obj => guid.register(obj, "dynamic"))
|
||||||
}
|
}
|
||||||
|
|
||||||
private def MakeBuildings(implicit context : ActorContext) : PairMap[Int, Building] = {
|
private def MakeBuildings(implicit context : ActorContext) : PairMap[Int, Building] = {
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ package net.psforever.packet.game.objectcreate
|
||||||
|
|
||||||
import net.psforever.newcodecs.newcodecs
|
import net.psforever.newcodecs.newcodecs
|
||||||
import net.psforever.packet.{Marshallable, PacketHelpers}
|
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.{Attempt, Codec}
|
||||||
import scodec.codecs._
|
import scodec.codecs._
|
||||||
import shapeless.{::, HNil}
|
import shapeless.{::, HNil}
|
||||||
|
|
@ -71,6 +71,8 @@ final case class DCDExtra2(unk1 : Int,
|
||||||
* range is 0-65535
|
* range is 0-65535
|
||||||
* @param stamina for `x / y` of stamina points, this is the avatar's `x` value;
|
* @param stamina for `x / y` of stamina points, this is the avatar's `x` value;
|
||||||
* range is 0-65535
|
* 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
|
* @param certs the `List` of certifications
|
||||||
*/
|
*/
|
||||||
final case class DetailedCharacterA(bep : Long,
|
final case class DetailedCharacterA(bep : Long,
|
||||||
|
|
@ -85,14 +87,16 @@ final case class DetailedCharacterA(bep : Long,
|
||||||
unk5 : Long,
|
unk5 : Long,
|
||||||
staminaMax : Int,
|
staminaMax : Int,
|
||||||
stamina : Int,
|
stamina : Int,
|
||||||
|
max_field : Option[Long],
|
||||||
unk6 : Int,
|
unk6 : Int,
|
||||||
unk7 : Int,
|
unk7 : Int,
|
||||||
unk8 : Long,
|
unk8 : Long,
|
||||||
unk9 : List[Int],
|
unk9 : List[Int],
|
||||||
certs : List[CertificationType.Value]) extends StreamBitSize {
|
certs : List[CertificationType.Value]) extends StreamBitSize {
|
||||||
override def bitsize : Long = {
|
override def bitsize : Long = {
|
||||||
|
val maxFieldSize = max_field match { case Some(_) => 32L ; case None => 0L }
|
||||||
val certSize : Long = certs.length * 8
|
val certSize : Long = certs.length * 8
|
||||||
428L + certSize
|
428L + maxFieldSize + certSize
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -197,6 +201,7 @@ object DetailedCharacterData extends Marshallable[DetailedCharacterData] {
|
||||||
armor : Int,
|
armor : Int,
|
||||||
staminaMax : Int,
|
staminaMax : Int,
|
||||||
stamina : Int,
|
stamina : Int,
|
||||||
|
maxField : Option[Long],
|
||||||
certs : List[CertificationType.Value],
|
certs : List[CertificationType.Value],
|
||||||
implants : List[ImplantEntry],
|
implants : List[ImplantEntry],
|
||||||
firstTimeEvents : List[String],
|
firstTimeEvents : List[String],
|
||||||
|
|
@ -213,6 +218,7 @@ object DetailedCharacterData extends Marshallable[DetailedCharacterData] {
|
||||||
armor,
|
armor,
|
||||||
0L,
|
0L,
|
||||||
staminaMax, stamina,
|
staminaMax, stamina,
|
||||||
|
maxField,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
0L,
|
0L,
|
||||||
|
|
@ -527,7 +533,7 @@ object DetailedCharacterData extends Marshallable[DetailedCharacterData] {
|
||||||
*/
|
*/
|
||||||
def isBR24(bep : Long) : Boolean = bep > 2286230
|
def isBR24(bep : Long) : Boolean = bep > 2286230
|
||||||
|
|
||||||
val a_codec : Codec[DetailedCharacterA] = (
|
def a_codec(suit : ExoSuitType.Value) : Codec[DetailedCharacterA] = (
|
||||||
("bep" | uint32L) ::
|
("bep" | uint32L) ::
|
||||||
("cep" | uint32L) ::
|
("cep" | uint32L) ::
|
||||||
("unk1" | uint32L) ::
|
("unk1" | uint32L) ::
|
||||||
|
|
@ -540,7 +546,7 @@ object DetailedCharacterData extends Marshallable[DetailedCharacterData] {
|
||||||
("unk5" | uint32) :: //endianness?
|
("unk5" | uint32) :: //endianness?
|
||||||
("staminaMax" | uint16L) ::
|
("staminaMax" | uint16L) ::
|
||||||
("stamina" | uint16L) ::
|
("stamina" | uint16L) ::
|
||||||
conditional(false, uint32L) :: //see ps.c: sub_901150, line#1070692
|
conditional(suit == ExoSuitType.MAX, uint32L) ::
|
||||||
("unk6" | uint16L) ::
|
("unk6" | uint16L) ::
|
||||||
("unk7" | uint(3)) ::
|
("unk7" | uint(3)) ::
|
||||||
("unk8" | uint32L) ::
|
("unk8" | uint32L) ::
|
||||||
|
|
@ -548,13 +554,13 @@ object DetailedCharacterData extends Marshallable[DetailedCharacterData] {
|
||||||
("certs" | listOfN(uint8L, CertificationType.codec))
|
("certs" | listOfN(uint8L, CertificationType.codec))
|
||||||
).exmap[DetailedCharacterA] (
|
).exmap[DetailedCharacterA] (
|
||||||
{
|
{
|
||||||
case bep :: cep :: u1 :: u2 :: u3 :: healthMax :: health :: u4 :: armor :: u5 :: staminaMax :: stamina :: None :: u6 :: u7 :: u8 :: u9 :: certs :: HNil =>
|
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, u6, u7, u8, u9, certs))
|
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(
|
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] = (
|
def codec(suit : ExoSuitType.Value, pad_length : Option[Int]) : Codec[DetailedCharacterData] = (
|
||||||
("a" | a_codec) >>:~ { a =>
|
("a" | a_codec(suit)) >>:~ { a =>
|
||||||
("b" | b_codec(a.bep, pad_length)).hlist
|
("b" | b_codec(a.bep, pad_length)).hlist
|
||||||
}
|
}
|
||||||
).exmap[DetailedCharacterData] (
|
).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)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -114,7 +114,7 @@ object DetailedPlayerData extends Marshallable[DetailedPlayerData] {
|
||||||
def codec(position_defined : Boolean) : Codec[DetailedPlayerData] = (
|
def codec(position_defined : Boolean) : Codec[DetailedPlayerData] = (
|
||||||
conditional(position_defined, "pos" | PlacementData.codec) >>:~ { pos =>
|
conditional(position_defined, "pos" | PlacementData.codec) >>:~ { pos =>
|
||||||
("basic_appearance" | CharacterAppearanceData.codec(PlayerData.PaddingOffset(pos))) >>:~ { app =>
|
("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) ::
|
optional(bool, "inventory" | InventoryData.codec_detailed) ::
|
||||||
("drawn_slot" | DrawnSlot.codec) ::
|
("drawn_slot" | DrawnSlot.codec) ::
|
||||||
bool //usually false
|
bool //usually false
|
||||||
|
|
|
||||||
File diff suppressed because one or more lines are too long
|
|
@ -1460,17 +1460,17 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
//remove potential MAX weapon
|
//remove potential MAX weapon
|
||||||
|
tplayer.DrawnSlot = Player.HandsDownSlot
|
||||||
|
sendResponse(ObjectHeldMessage(tplayer.GUID, Player.HandsDownSlot, true))
|
||||||
val normalWeapons = if(originalSuit == ExoSuitType.MAX) {
|
val normalWeapons = if(originalSuit == ExoSuitType.MAX) {
|
||||||
val (maxWeapons, normalWeapons) = beforeHolsters.partition(elem => elem.obj.Size == EquipmentSize.Max)
|
val (maxWeapons, normalWeapons) = beforeHolsters.partition(elem => elem.obj.Size == EquipmentSize.Max)
|
||||||
maxWeapons.foreach(entry => {
|
maxWeapons.foreach(entry => {
|
||||||
taskResolver ! GUIDTask.UnregisterEquipment(entry.obj)(continent.GUID)
|
taskResolver ! GUIDTask.UnregisterEquipment(entry.obj)(continent.GUID)
|
||||||
})
|
})
|
||||||
|
avatarService ! AvatarServiceMessage(player.Continent, AvatarAction.ObjectHeld(player.GUID, player.LastDrawnSlot))
|
||||||
normalWeapons
|
normalWeapons
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
tplayer.DrawnSlot = Player.HandsDownSlot
|
|
||||||
sendResponse(ObjectHeldMessage(tplayer.GUID, Player.HandsDownSlot, true))
|
|
||||||
avatarService ! AvatarServiceMessage(tplayer.Continent, AvatarAction.ObjectHeld(tplayer.GUID, Player.HandsDownSlot))
|
|
||||||
beforeHolsters
|
beforeHolsters
|
||||||
}
|
}
|
||||||
//fill holsters
|
//fill holsters
|
||||||
|
|
@ -2879,7 +2879,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
||||||
//we're driving the vehicle
|
//we're driving the vehicle
|
||||||
player.Position = pos //convenient
|
player.Position = pos //convenient
|
||||||
if(seat.ControlledWeapon.isEmpty) {
|
if(seat.ControlledWeapon.isEmpty) {
|
||||||
player.Orientation = Vector3(0f, 0f, ang.z) //convenient
|
player.Orientation = Vector3.z(ang.z) //convenient
|
||||||
}
|
}
|
||||||
obj.Position = pos
|
obj.Position = pos
|
||||||
obj.Orientation = ang
|
obj.Orientation = ang
|
||||||
|
|
|
||||||
|
|
@ -476,6 +476,7 @@ class PacketCodingActorITest extends ActorTest {
|
||||||
100, 100,
|
100, 100,
|
||||||
50,
|
50,
|
||||||
100, 100,
|
100, 100,
|
||||||
|
None,
|
||||||
List(CertificationType.StandardAssault, CertificationType.MediumAssault, CertificationType.ATV, CertificationType.Harasser, CertificationType.StandardExoSuit, CertificationType.AgileExoSuit, CertificationType.ReinforcedExoSuit),
|
List(CertificationType.StandardAssault, CertificationType.MediumAssault, CertificationType.ATV, CertificationType.Harasser, CertificationType.StandardExoSuit, CertificationType.AgileExoSuit, CertificationType.ReinforcedExoSuit),
|
||||||
List(),
|
List(),
|
||||||
List(),
|
List(),
|
||||||
|
|
@ -601,6 +602,7 @@ class PacketCodingActorKTest extends ActorTest {
|
||||||
50,
|
50,
|
||||||
32831L,
|
32831L,
|
||||||
100, 100,
|
100, 100,
|
||||||
|
None,
|
||||||
0, 0, 0L,
|
0, 0, 0L,
|
||||||
List(0, 0, 0, 0, 0, 0),
|
List(0, 0, 0, 0, 0, 0),
|
||||||
List(
|
List(
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue