From 91d52ee27773cd7f170af811335f5239898b4355 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Thu, 15 Apr 2021 13:00:14 +0000 Subject: [PATCH 01/13] Update akka to v2.6.14 --- build.sbt | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/build.sbt b/build.sbt index 2fc81a7d..e46fc9ca 100644 --- a/build.sbt +++ b/build.sbt @@ -40,16 +40,16 @@ lazy val psforeverSettings = Seq( classLoaderLayeringStrategy := ClassLoaderLayeringStrategy.Flat, resolvers += "Sonatype OSS Snapshots" at "https://oss.sonatype.org/content/repositories/snapshots", libraryDependencies ++= Seq( - "com.typesafe.akka" %% "akka-actor" % "2.6.13", - "com.typesafe.akka" %% "akka-slf4j" % "2.6.13", - "com.typesafe.akka" %% "akka-protobuf-v3" % "2.6.13", - "com.typesafe.akka" %% "akka-stream" % "2.6.13", - "com.typesafe.akka" %% "akka-testkit" % "2.6.13" % "test", - "com.typesafe.akka" %% "akka-actor-typed" % "2.6.13", - "com.typesafe.akka" %% "akka-cluster-typed" % "2.6.13", - "com.typesafe.akka" %% "akka-coordination" % "2.6.13", - "com.typesafe.akka" %% "akka-cluster-tools" % "2.6.13", - "com.typesafe.akka" %% "akka-slf4j" % "2.6.13", + "com.typesafe.akka" %% "akka-actor" % "2.6.14", + "com.typesafe.akka" %% "akka-slf4j" % "2.6.14", + "com.typesafe.akka" %% "akka-protobuf-v3" % "2.6.14", + "com.typesafe.akka" %% "akka-stream" % "2.6.14", + "com.typesafe.akka" %% "akka-testkit" % "2.6.14" % "test", + "com.typesafe.akka" %% "akka-actor-typed" % "2.6.14", + "com.typesafe.akka" %% "akka-cluster-typed" % "2.6.14", + "com.typesafe.akka" %% "akka-coordination" % "2.6.14", + "com.typesafe.akka" %% "akka-cluster-tools" % "2.6.14", + "com.typesafe.akka" %% "akka-slf4j" % "2.6.14", "com.typesafe.akka" %% "akka-http" % "10.2.4", "com.typesafe.scala-logging" %% "scala-logging" % "3.9.3", "org.specs2" %% "specs2-core" % "4.10.6" % "test", From b63fcd8c12f24bc69955b9ff19bab95aa61a28dc Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Fri, 16 Apr 2021 13:18:13 +0000 Subject: [PATCH 02/13] Update dependency org.flywaydb:flyway-core to v7.8.1 --- build.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.sbt b/build.sbt index e46fc9ca..a2ffa89a 100644 --- a/build.sbt +++ b/build.sbt @@ -66,7 +66,7 @@ lazy val psforeverSettings = Seq( "io.kamon" %% "kamon-apm-reporter" % "2.1.15", "org.json4s" %% "json4s-native" % "3.6.11", "io.getquill" %% "quill-jasync-postgres" % "3.7.0", - "org.flywaydb" % "flyway-core" % "7.7.3", + "org.flywaydb" % "flyway-core" % "7.8.1", "org.postgresql" % "postgresql" % "42.2.19", "com.typesafe" % "config" % "1.4.1", "com.github.pureconfig" %% "pureconfig" % "0.14.1", From cfeff70c6b5b7fb3b3a4a761d767767cc6a19d28 Mon Sep 17 00:00:00 2001 From: "Jason_DiDonato@yahoo.com" Date: Fri, 16 Apr 2021 07:59:18 -0400 Subject: [PATCH 03/13] adjusting deadState thus that the player is not set to 'Alive' during avatar create prior to avatar setup --- .../net/psforever/actors/session/SessionActor.scala | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/main/scala/net/psforever/actors/session/SessionActor.scala b/src/main/scala/net/psforever/actors/session/SessionActor.scala index 44968a75..32e1345a 100644 --- a/src/main/scala/net/psforever/actors/session/SessionActor.scala +++ b/src/main/scala/net/psforever/actors/session/SessionActor.scala @@ -3125,7 +3125,9 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con player.Actor ! JammableUnit.ClearJammeredStatus() player.Actor ! JammableUnit.ClearJammeredSound() } - if (deadState != DeadState.Alive) { + val originalDeadState = deadState + deadState = DeadState.Alive + if (originalDeadState != DeadState.Alive) { avatarActor ! AvatarActor.ResetImplants() } @@ -3139,8 +3141,6 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con sendResponse( SetChatFilterMessage(ChatChannel.Platoon, false, ChatChannel.values.toList) ) //TODO will not always be "on" like this - val originalDeadState = deadState - deadState = DeadState.Alive sendResponse(AvatarDeadStateMessage(DeadState.Alive, 0, 0, tplayer.Position, player.Faction, true)) //looking for squad (members) if (tplayer.avatar.lookingForSquad || lfsm) { @@ -7090,8 +7090,6 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con log.trace(s"AvatarCreate: ${player.Name} - $guid -> $data") } continent.Population ! Zone.Population.Spawn(avatar, player, avatarActor) - //cautious redundancy - deadState = DeadState.Alive avatarActor ! AvatarActor.RefreshPurchaseTimes() //begin looking for conditions to set the avatar context.system.scheduler.scheduleOnce(delay = 250 millisecond, self, SetCurrentAvatar(player, 200)) @@ -7278,8 +7276,6 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con sendResponse(ObjectCreateDetailedMessage(ObjectClass.avatar, guid, data)) log.debug(s"AvatarRejoin: ${player.Name} - $guid -> $data") } - //cautious redundancy - deadState = DeadState.Alive avatarActor ! AvatarActor.RefreshPurchaseTimes() setupAvatarFunc = AvatarCreate //begin looking for conditions to set the avatar From 92a0b1dfaac3cca95f9e72f6bc2ce36756ecbcb6 Mon Sep 17 00:00:00 2001 From: Jakob Gillich Date: Fri, 16 Apr 2021 21:37:20 +0200 Subject: [PATCH 04/13] Implant initialization fixes --- .../actors/session/AvatarActor.scala | 51 +- .../psforever/objects/GlobalDefinitions.scala | 654 +++++++++--------- 2 files changed, 368 insertions(+), 337 deletions(-) diff --git a/src/main/scala/net/psforever/actors/session/AvatarActor.scala b/src/main/scala/net/psforever/actors/session/AvatarActor.scala index 38fecd82..1020284d 100644 --- a/src/main/scala/net/psforever/actors/session/AvatarActor.scala +++ b/src/main/scala/net/psforever/actors/session/AvatarActor.scala @@ -207,6 +207,8 @@ object AvatarActor { private case class SetStamina(stamina: Int) extends Command + private case class SetImplantInitialized(implantType: ImplantType) extends Command + final case class AvatarResponse(avatar: Avatar) final case class AvatarLoginResponse(avatar: Avatar) @@ -486,14 +488,14 @@ class AvatarActor( ) } else { var requiredByCert: Set[Certification] = Set(certification) - var removeThese: Set[Certification] = Set(certification) - val allCerts: Set[Certification] = Certification.values.toSet + var removeThese: Set[Certification] = Set(certification) + val allCerts: Set[Certification] = Certification.values.toSet do { removeThese = allCerts.filter { testingCert => testingCert.requires.intersect(removeThese).nonEmpty } requiredByCert = requiredByCert ++ removeThese - } while(removeThese.nonEmpty) + } while (removeThese.nonEmpty) Future .sequence( @@ -777,10 +779,9 @@ class AvatarActor( Behaviors.same case ActivateImplant(implantType) => - val res = avatar.implants.zipWithIndex.collectFirst { + avatar.implants.zipWithIndex.collectFirst { case (Some(implant), index) if implant.definition.implantType == implantType => (implant, index) - } - res match { + } match { case Some((implant, slot)) => if (!implant.initialized) { log.error(s"requested activation of uninitialized implant $implant") @@ -831,6 +832,31 @@ class AvatarActor( } Behaviors.same + case SetImplantInitialized(implantType) => + avatar.implants.zipWithIndex.collectFirst { + case (Some(implant), index) if implant.definition.implantType == implantType => index + } match { + case Some(index) => + sessionActor ! SessionActor.SendResponse( + AvatarImplantMessage(session.get.player.GUID, ImplantAction.Initialization, index, 1) + ) + avatar = avatar.copy(implants = avatar.implants.map { + case Some(implant) if implant.definition.implantType == implantType => + Some(implant.copy(initialized = true)) + case other => other + }) + + // automatic targeting implant activation is a client side feature + // For some reason it doesn't always work with 100% reliability, so we're also activating it server side + // Must be delayed by a bit or the client will toggle it off again + if (implantType == ImplantType.Targeting) { + context.scheduleOnce(2.seconds, context.self, ActivateImplant(implantType)) + } + case None => log.error(s"set initialized called for unknown implant $implantType") + } + + Behaviors.same + case DeactivateImplant(implantType) => deactivateImplant(implantType) Behaviors.same @@ -1054,17 +1080,10 @@ class AvatarActor( ) implantTimers.get(slot).foreach(_.cancel()) - implantTimers(slot) = context.system.scheduler.scheduleOnce( + implantTimers(slot) = context.scheduleOnce( implant.definition.InitializationDuration.seconds, - () => { - avatar = avatar.copy(implants = avatar.implants.map { - case Some(implant) => Some(implant.copy(initialized = true)) - case None => None - }) - sessionActor ! SessionActor.SendResponse( - AvatarImplantMessage(session.get.player.GUID, ImplantAction.Initialization, slot, 1) - ) - } + context.self, + SetImplantInitialized(implant.definition.implantType) ) case (None, _) => ; diff --git a/src/main/scala/net/psforever/objects/GlobalDefinitions.scala b/src/main/scala/net/psforever/objects/GlobalDefinitions.scala index d768f0a2..77d05c27 100644 --- a/src/main/scala/net/psforever/objects/GlobalDefinitions.scala +++ b/src/main/scala/net/psforever/objects/GlobalDefinitions.scala @@ -20,7 +20,12 @@ import net.psforever.objects.serverobject.painbox.PainboxDefinition import net.psforever.objects.serverobject.terminals._ import net.psforever.objects.serverobject.tube.SpawnTubeDefinition import net.psforever.objects.serverobject.resourcesilo.ResourceSiloDefinition -import net.psforever.objects.serverobject.structures.{AmenityDefinition, AutoRepairStats, BuildingDefinition, WarpGateDefinition} +import net.psforever.objects.serverobject.structures.{ + AmenityDefinition, + AutoRepairStats, + BuildingDefinition, + WarpGateDefinition +} import net.psforever.objects.serverobject.terminals.capture.CaptureTerminalDefinition import net.psforever.objects.serverobject.terminals.implant.{ImplantTerminalDefinition, ImplantTerminalMechDefinition} import net.psforever.objects.serverobject.turret.{FacilityTurretDefinition, TurretUpgrade} @@ -1105,7 +1110,7 @@ object GlobalDefinitions { val generator = new GeneratorDefinition(351) - val obbasemesh = new AmenityDefinition(598) { } + val obbasemesh = new AmenityDefinition(598) {} initMiscellaneous() /* @@ -3742,7 +3747,7 @@ object GlobalDefinitions { ProjectileDefinition.CalculateDerivedFields(quasar_projectile) radiator_grenade_projectile.Name = "radiator_grenade_projectile" // Todo : Radiator damages ? - radiator_grenade_projectile.GrenadeProjectile = true //not really, but technically yes + radiator_grenade_projectile.GrenadeProjectile = true //not really, but technically yes radiator_grenade_projectile.ProjectileDamageType = DamageType.Direct radiator_grenade_projectile.InitialVelocity = 30 radiator_grenade_projectile.Lifespan = 3f @@ -4751,7 +4756,7 @@ object GlobalDefinitions { pellet_gun.FireModes.head.AmmoTypeIndices += 0 pellet_gun.FireModes.head.AmmoSlotIndex = 0 pellet_gun.FireModes.head.Magazine = 1 //what is this? - pellet_gun.FireModes.head.Chamber = 8 //1 shell * 8 pellets = 8 + pellet_gun.FireModes.head.Chamber = 8 //1 shell * 8 pellets = 8 pellet_gun.Tile = InventoryTile.Tile63 six_shooter.Name = "six_shooter" @@ -5619,9 +5624,9 @@ object GlobalDefinitions { * Initialize `VehicleDefinition` globals. */ private def init_vehicles(): Unit = { - val atvForm = GeometryForm.representByCylinder(radius = 1.1797f, height = 1.1875f) _ + val atvForm = GeometryForm.representByCylinder(radius = 1.1797f, height = 1.1875f) _ val delivererForm = GeometryForm.representByCylinder(radius = 2.46095f, height = 2.40626f) _ //TODO hexahedron - val apcForm = GeometryForm.representByCylinder(radius = 4.6211f, height = 3.90626f) _ //TODO hexahedron + val apcForm = GeometryForm.representByCylinder(radius = 4.6211f, height = 3.90626f) _ //TODO hexahedron val liberatorForm = GeometryForm.representByCylinder(radius = 3.74615f, height = 2.51563f) _ val bailableSeat = new SeatDefinition() { @@ -5637,11 +5642,11 @@ object GlobalDefinitions { fury.Repairable = true fury.RepairIfDestroyed = false fury.MaxShields = 130 - fury.Seats += 0 -> bailableSeat + fury.Seats += 0 -> bailableSeat fury.controlledWeapons += 0 -> 1 - fury.Weapons += 1 -> fury_weapon_systema - fury.MountPoints += 1 -> MountInfo(0) - fury.MountPoints += 2 -> MountInfo(0) + fury.Weapons += 1 -> fury_weapon_systema + fury.MountPoints += 1 -> MountInfo(0) + fury.MountPoints += 2 -> MountInfo(0) fury.TrunkSize = InventoryTile.Tile1111 fury.TrunkOffset = 30 fury.TrunkLocation = Vector3(-1.71f, 0f, 0f) @@ -5668,11 +5673,11 @@ object GlobalDefinitions { quadassault.Repairable = true quadassault.RepairIfDestroyed = false quadassault.MaxShields = 130 - quadassault.Seats += 0 -> bailableSeat + quadassault.Seats += 0 -> bailableSeat quadassault.controlledWeapons += 0 -> 1 - quadassault.Weapons += 1 -> quadassault_weapon_system - quadassault.MountPoints += 1 -> MountInfo(0) - quadassault.MountPoints += 2 -> MountInfo(0) + quadassault.Weapons += 1 -> quadassault_weapon_system + quadassault.MountPoints += 1 -> MountInfo(0) + quadassault.MountPoints += 2 -> MountInfo(0) quadassault.TrunkSize = InventoryTile.Tile1111 quadassault.TrunkOffset = 30 quadassault.TrunkLocation = Vector3(-1.71f, 0f, 0f) @@ -5730,12 +5735,12 @@ object GlobalDefinitions { two_man_assault_buggy.Repairable = true two_man_assault_buggy.RepairIfDestroyed = false two_man_assault_buggy.MaxShields = 250 - two_man_assault_buggy.Seats += 0 -> bailableSeat - two_man_assault_buggy.Seats += 1 -> bailableSeat + two_man_assault_buggy.Seats += 0 -> bailableSeat + two_man_assault_buggy.Seats += 1 -> bailableSeat two_man_assault_buggy.controlledWeapons += 1 -> 2 - two_man_assault_buggy.Weapons += 2 -> chaingun_p - two_man_assault_buggy.MountPoints += 1 -> MountInfo(0) - two_man_assault_buggy.MountPoints += 2 -> MountInfo(1) + two_man_assault_buggy.Weapons += 2 -> chaingun_p + two_man_assault_buggy.MountPoints += 1 -> MountInfo(0) + two_man_assault_buggy.MountPoints += 2 -> MountInfo(1) two_man_assault_buggy.TrunkSize = InventoryTile.Tile1511 two_man_assault_buggy.TrunkOffset = 30 two_man_assault_buggy.TrunkLocation = Vector3(-2.5f, 0f, 0f) @@ -5762,13 +5767,13 @@ object GlobalDefinitions { skyguard.Repairable = true skyguard.RepairIfDestroyed = false skyguard.MaxShields = 200 - skyguard.Seats += 0 -> bailableSeat - skyguard.Seats += 1 -> bailableSeat + skyguard.Seats += 0 -> bailableSeat + skyguard.Seats += 1 -> bailableSeat skyguard.controlledWeapons += 1 -> 2 - skyguard.Weapons += 2 -> skyguard_weapon_system - skyguard.MountPoints += 1 -> MountInfo(0) - skyguard.MountPoints += 2 -> MountInfo(0) - skyguard.MountPoints += 3 -> MountInfo(1) + skyguard.Weapons += 2 -> skyguard_weapon_system + skyguard.MountPoints += 1 -> MountInfo(0) + skyguard.MountPoints += 2 -> MountInfo(0) + skyguard.MountPoints += 3 -> MountInfo(1) skyguard.TrunkSize = InventoryTile.Tile1511 skyguard.TrunkOffset = 30 skyguard.TrunkLocation = Vector3(2.5f, 0f, 0f) @@ -5795,16 +5800,16 @@ object GlobalDefinitions { threemanheavybuggy.Repairable = true threemanheavybuggy.RepairIfDestroyed = false threemanheavybuggy.MaxShields = 340 - threemanheavybuggy.Seats += 0 -> bailableSeat - threemanheavybuggy.Seats += 1 -> bailableSeat - threemanheavybuggy.Seats += 2 -> bailableSeat + threemanheavybuggy.Seats += 0 -> bailableSeat + threemanheavybuggy.Seats += 1 -> bailableSeat + threemanheavybuggy.Seats += 2 -> bailableSeat threemanheavybuggy.controlledWeapons += 1 -> 3 threemanheavybuggy.controlledWeapons += 2 -> 4 - threemanheavybuggy.Weapons += 3 -> chaingun_p - threemanheavybuggy.Weapons += 4 -> grenade_launcher_marauder - threemanheavybuggy.MountPoints += 1 -> MountInfo(0) - threemanheavybuggy.MountPoints += 2 -> MountInfo(1) - threemanheavybuggy.MountPoints += 3 -> MountInfo(2) + threemanheavybuggy.Weapons += 3 -> chaingun_p + threemanheavybuggy.Weapons += 4 -> grenade_launcher_marauder + threemanheavybuggy.MountPoints += 1 -> MountInfo(0) + threemanheavybuggy.MountPoints += 2 -> MountInfo(1) + threemanheavybuggy.MountPoints += 3 -> MountInfo(2) threemanheavybuggy.TrunkSize = InventoryTile.Tile1511 threemanheavybuggy.TrunkOffset = 30 threemanheavybuggy.TrunkLocation = Vector3(3.01f, 0f, 0f) @@ -5832,12 +5837,12 @@ object GlobalDefinitions { twomanheavybuggy.Repairable = true twomanheavybuggy.RepairIfDestroyed = false twomanheavybuggy.MaxShields = 360 - twomanheavybuggy.Seats += 0 -> bailableSeat - twomanheavybuggy.Seats += 1 -> bailableSeat + twomanheavybuggy.Seats += 0 -> bailableSeat + twomanheavybuggy.Seats += 1 -> bailableSeat twomanheavybuggy.controlledWeapons += 1 -> 2 - twomanheavybuggy.Weapons += 2 -> advanced_missile_launcher_t - twomanheavybuggy.MountPoints += 1 -> MountInfo(0) - twomanheavybuggy.MountPoints += 2 -> MountInfo(1) + twomanheavybuggy.Weapons += 2 -> advanced_missile_launcher_t + twomanheavybuggy.MountPoints += 1 -> MountInfo(0) + twomanheavybuggy.MountPoints += 2 -> MountInfo(1) twomanheavybuggy.TrunkSize = InventoryTile.Tile1511 twomanheavybuggy.TrunkOffset = 30 twomanheavybuggy.TrunkLocation = Vector3(-0.23f, -2.05f, 0f) @@ -5865,12 +5870,12 @@ object GlobalDefinitions { twomanhoverbuggy.Repairable = true twomanhoverbuggy.RepairIfDestroyed = false twomanhoverbuggy.MaxShields = 320 - twomanhoverbuggy.Seats += 0 -> bailableSeat - twomanhoverbuggy.Seats += 1 -> bailableSeat + twomanhoverbuggy.Seats += 0 -> bailableSeat + twomanhoverbuggy.Seats += 1 -> bailableSeat twomanhoverbuggy.controlledWeapons += 1 -> 2 - twomanhoverbuggy.Weapons += 2 -> flux_cannon_thresher - twomanhoverbuggy.MountPoints += 1 -> MountInfo(0) - twomanhoverbuggy.MountPoints += 2 -> MountInfo(1) + twomanhoverbuggy.Weapons += 2 -> flux_cannon_thresher + twomanhoverbuggy.MountPoints += 1 -> MountInfo(0) + twomanhoverbuggy.MountPoints += 2 -> MountInfo(1) twomanhoverbuggy.TrunkSize = InventoryTile.Tile1511 twomanhoverbuggy.TrunkOffset = 30 twomanhoverbuggy.TrunkLocation = Vector3(-3.39f, 0f, 0f) @@ -5888,7 +5893,10 @@ object GlobalDefinitions { Modifiers = ExplodingRadialDegrade } twomanhoverbuggy.DrownAtMaxDepth = true - twomanhoverbuggy.UnderwaterLifespan(suffocation = 45000L, recovery = 5000L) //but the thresher hovers over water, so ...? + twomanhoverbuggy.UnderwaterLifespan( + suffocation = 45000L, + recovery = 5000L + ) //but the thresher hovers over water, so ...? twomanhoverbuggy.Geometry = GeometryForm.representByCylinder(radius = 2.1875f, height = 2.01563f) mediumtransport.Name = "mediumtransport" // Deliverer @@ -5900,19 +5908,19 @@ object GlobalDefinitions { mediumtransport.Seats += 0 -> new SeatDefinition() { restriction = NoReinforcedOrMax } - mediumtransport.Seats += 1 -> new SeatDefinition() - mediumtransport.Seats += 2 -> new SeatDefinition() - mediumtransport.Seats += 3 -> new SeatDefinition() - mediumtransport.Seats += 4 -> new SeatDefinition() + mediumtransport.Seats += 1 -> new SeatDefinition() + mediumtransport.Seats += 2 -> new SeatDefinition() + mediumtransport.Seats += 3 -> new SeatDefinition() + mediumtransport.Seats += 4 -> new SeatDefinition() mediumtransport.controlledWeapons += 1 -> 5 mediumtransport.controlledWeapons += 2 -> 6 - mediumtransport.Weapons += 5 -> mediumtransport_weapon_systemA - mediumtransport.Weapons += 6 -> mediumtransport_weapon_systemB - mediumtransport.MountPoints += 1 -> MountInfo(0) - mediumtransport.MountPoints += 2 -> MountInfo(1) - mediumtransport.MountPoints += 3 -> MountInfo(2) - mediumtransport.MountPoints += 4 -> MountInfo(3) - mediumtransport.MountPoints += 5 -> MountInfo(4) + mediumtransport.Weapons += 5 -> mediumtransport_weapon_systemA + mediumtransport.Weapons += 6 -> mediumtransport_weapon_systemB + mediumtransport.MountPoints += 1 -> MountInfo(0) + mediumtransport.MountPoints += 2 -> MountInfo(1) + mediumtransport.MountPoints += 3 -> MountInfo(2) + mediumtransport.MountPoints += 4 -> MountInfo(3) + mediumtransport.MountPoints += 5 -> MountInfo(4) mediumtransport.TrunkSize = InventoryTile.Tile1515 mediumtransport.TrunkOffset = 30 mediumtransport.TrunkLocation = Vector3(-3.46f, 0f, 0f) @@ -5943,23 +5951,23 @@ object GlobalDefinitions { battlewagon.Seats += 0 -> new SeatDefinition() { restriction = NoReinforcedOrMax } - battlewagon.Seats += 1 -> new SeatDefinition() - battlewagon.Seats += 2 -> new SeatDefinition() - battlewagon.Seats += 3 -> new SeatDefinition() - battlewagon.Seats += 4 -> new SeatDefinition() + battlewagon.Seats += 1 -> new SeatDefinition() + battlewagon.Seats += 2 -> new SeatDefinition() + battlewagon.Seats += 3 -> new SeatDefinition() + battlewagon.Seats += 4 -> new SeatDefinition() battlewagon.controlledWeapons += 1 -> 5 battlewagon.controlledWeapons += 2 -> 6 battlewagon.controlledWeapons += 3 -> 7 battlewagon.controlledWeapons += 4 -> 8 - battlewagon.Weapons += 5 -> battlewagon_weapon_systema - battlewagon.Weapons += 6 -> battlewagon_weapon_systemb - battlewagon.Weapons += 7 -> battlewagon_weapon_systemc - battlewagon.Weapons += 8 -> battlewagon_weapon_systemd - battlewagon.MountPoints += 1 -> MountInfo(0) - battlewagon.MountPoints += 2 -> MountInfo(1) - battlewagon.MountPoints += 3 -> MountInfo(2) - battlewagon.MountPoints += 4 -> MountInfo(3) - battlewagon.MountPoints += 5 -> MountInfo(4) + battlewagon.Weapons += 5 -> battlewagon_weapon_systema + battlewagon.Weapons += 6 -> battlewagon_weapon_systemb + battlewagon.Weapons += 7 -> battlewagon_weapon_systemc + battlewagon.Weapons += 8 -> battlewagon_weapon_systemd + battlewagon.MountPoints += 1 -> MountInfo(0) + battlewagon.MountPoints += 2 -> MountInfo(1) + battlewagon.MountPoints += 3 -> MountInfo(2) + battlewagon.MountPoints += 4 -> MountInfo(3) + battlewagon.MountPoints += 5 -> MountInfo(4) battlewagon.TrunkSize = InventoryTile.Tile1515 battlewagon.TrunkOffset = 30 battlewagon.TrunkLocation = Vector3(-3.46f, 0f, 0f) @@ -5989,19 +5997,19 @@ object GlobalDefinitions { thunderer.Seats += 0 -> new SeatDefinition() { restriction = NoReinforcedOrMax } - thunderer.Seats += 1 -> new SeatDefinition() - thunderer.Seats += 2 -> new SeatDefinition() - thunderer.Seats += 3 -> new SeatDefinition() - thunderer.Seats += 4 -> new SeatDefinition() - thunderer.Weapons += 5 -> thunderer_weapon_systema - thunderer.Weapons += 6 -> thunderer_weapon_systemb + thunderer.Seats += 1 -> new SeatDefinition() + thunderer.Seats += 2 -> new SeatDefinition() + thunderer.Seats += 3 -> new SeatDefinition() + thunderer.Seats += 4 -> new SeatDefinition() + thunderer.Weapons += 5 -> thunderer_weapon_systema + thunderer.Weapons += 6 -> thunderer_weapon_systemb thunderer.controlledWeapons += 1 -> 5 thunderer.controlledWeapons += 2 -> 6 - thunderer.MountPoints += 1 -> MountInfo(0) - thunderer.MountPoints += 2 -> MountInfo(1) - thunderer.MountPoints += 3 -> MountInfo(2) - thunderer.MountPoints += 4 -> MountInfo(3) - thunderer.MountPoints += 5 -> MountInfo(4) + thunderer.MountPoints += 1 -> MountInfo(0) + thunderer.MountPoints += 2 -> MountInfo(1) + thunderer.MountPoints += 3 -> MountInfo(2) + thunderer.MountPoints += 4 -> MountInfo(3) + thunderer.MountPoints += 5 -> MountInfo(4) thunderer.TrunkSize = InventoryTile.Tile1515 thunderer.TrunkOffset = 30 thunderer.TrunkLocation = Vector3(-3.46f, 0f, 0f) @@ -6032,19 +6040,19 @@ object GlobalDefinitions { aurora.Seats += 0 -> new SeatDefinition() { restriction = NoReinforcedOrMax } - aurora.Seats += 1 -> new SeatDefinition() - aurora.Seats += 2 -> new SeatDefinition() - aurora.Seats += 3 -> new SeatDefinition() - aurora.Seats += 4 -> new SeatDefinition() + aurora.Seats += 1 -> new SeatDefinition() + aurora.Seats += 2 -> new SeatDefinition() + aurora.Seats += 3 -> new SeatDefinition() + aurora.Seats += 4 -> new SeatDefinition() aurora.controlledWeapons += 1 -> 5 aurora.controlledWeapons += 2 -> 6 - aurora.Weapons += 5 -> aurora_weapon_systema - aurora.Weapons += 6 -> aurora_weapon_systemb - aurora.MountPoints += 1 -> MountInfo(0) - aurora.MountPoints += 2 -> MountInfo(1) - aurora.MountPoints += 3 -> MountInfo(2) - aurora.MountPoints += 4 -> MountInfo(3) - aurora.MountPoints += 5 -> MountInfo(4) + aurora.Weapons += 5 -> aurora_weapon_systema + aurora.Weapons += 6 -> aurora_weapon_systemb + aurora.MountPoints += 1 -> MountInfo(0) + aurora.MountPoints += 2 -> MountInfo(1) + aurora.MountPoints += 3 -> MountInfo(2) + aurora.MountPoints += 4 -> MountInfo(3) + aurora.MountPoints += 5 -> MountInfo(4) aurora.TrunkSize = InventoryTile.Tile1515 aurora.TrunkOffset = 30 aurora.TrunkLocation = Vector3(-3.46f, 0f, 0f) @@ -6072,41 +6080,41 @@ object GlobalDefinitions { apc_tr.Repairable = true apc_tr.RepairIfDestroyed = false apc_tr.MaxShields = 1200 - apc_tr.Seats += 0 -> new SeatDefinition() - apc_tr.Seats += 1 -> new SeatDefinition() - apc_tr.Seats += 2 -> new SeatDefinition() - apc_tr.Seats += 3 -> new SeatDefinition() - apc_tr.Seats += 4 -> new SeatDefinition() - apc_tr.Seats += 5 -> new SeatDefinition() - apc_tr.Seats += 6 -> new SeatDefinition() - apc_tr.Seats += 7 -> new SeatDefinition() - apc_tr.Seats += 8 -> new SeatDefinition() - apc_tr.Seats += 9 -> maxOnlySeat - apc_tr.Seats += 10 -> maxOnlySeat + apc_tr.Seats += 0 -> new SeatDefinition() + apc_tr.Seats += 1 -> new SeatDefinition() + apc_tr.Seats += 2 -> new SeatDefinition() + apc_tr.Seats += 3 -> new SeatDefinition() + apc_tr.Seats += 4 -> new SeatDefinition() + apc_tr.Seats += 5 -> new SeatDefinition() + apc_tr.Seats += 6 -> new SeatDefinition() + apc_tr.Seats += 7 -> new SeatDefinition() + apc_tr.Seats += 8 -> new SeatDefinition() + apc_tr.Seats += 9 -> maxOnlySeat + apc_tr.Seats += 10 -> maxOnlySeat apc_tr.controlledWeapons += 1 -> 11 apc_tr.controlledWeapons += 2 -> 12 apc_tr.controlledWeapons += 5 -> 15 apc_tr.controlledWeapons += 6 -> 16 apc_tr.controlledWeapons += 7 -> 13 apc_tr.controlledWeapons += 8 -> 14 - apc_tr.Weapons += 11 -> apc_weapon_systemc_tr - apc_tr.Weapons += 12 -> apc_weapon_systemb - apc_tr.Weapons += 13 -> apc_weapon_systema - apc_tr.Weapons += 14 -> apc_weapon_systemd_tr - apc_tr.Weapons += 15 -> apc_ballgun_r - apc_tr.Weapons += 16 -> apc_ballgun_l - apc_tr.MountPoints += 1 -> MountInfo(0) - apc_tr.MountPoints += 2 -> MountInfo(0) - apc_tr.MountPoints += 3 -> MountInfo(1) - apc_tr.MountPoints += 4 -> MountInfo(2) - apc_tr.MountPoints += 5 -> MountInfo(3) - apc_tr.MountPoints += 6 -> MountInfo(4) - apc_tr.MountPoints += 7 -> MountInfo(5) - apc_tr.MountPoints += 8 -> MountInfo(6) - apc_tr.MountPoints += 9 -> MountInfo(7) - apc_tr.MountPoints += 10 -> MountInfo(8) - apc_tr.MountPoints += 11 -> MountInfo(9) - apc_tr.MountPoints += 12 -> MountInfo(10) + apc_tr.Weapons += 11 -> apc_weapon_systemc_tr + apc_tr.Weapons += 12 -> apc_weapon_systemb + apc_tr.Weapons += 13 -> apc_weapon_systema + apc_tr.Weapons += 14 -> apc_weapon_systemd_tr + apc_tr.Weapons += 15 -> apc_ballgun_r + apc_tr.Weapons += 16 -> apc_ballgun_l + apc_tr.MountPoints += 1 -> MountInfo(0) + apc_tr.MountPoints += 2 -> MountInfo(0) + apc_tr.MountPoints += 3 -> MountInfo(1) + apc_tr.MountPoints += 4 -> MountInfo(2) + apc_tr.MountPoints += 5 -> MountInfo(3) + apc_tr.MountPoints += 6 -> MountInfo(4) + apc_tr.MountPoints += 7 -> MountInfo(5) + apc_tr.MountPoints += 8 -> MountInfo(6) + apc_tr.MountPoints += 9 -> MountInfo(7) + apc_tr.MountPoints += 10 -> MountInfo(8) + apc_tr.MountPoints += 11 -> MountInfo(9) + apc_tr.MountPoints += 12 -> MountInfo(10) apc_tr.TrunkSize = InventoryTile.Tile2016 apc_tr.TrunkOffset = 30 apc_tr.TrunkLocation = Vector3(-5.82f, 0f, 0f) @@ -6134,41 +6142,41 @@ object GlobalDefinitions { apc_nc.Repairable = true apc_nc.RepairIfDestroyed = false apc_nc.MaxShields = 1200 - apc_nc.Seats += 0 -> new SeatDefinition() - apc_nc.Seats += 1 -> new SeatDefinition() - apc_nc.Seats += 2 -> new SeatDefinition() - apc_nc.Seats += 3 -> new SeatDefinition() - apc_nc.Seats += 4 -> new SeatDefinition() - apc_nc.Seats += 5 -> new SeatDefinition() - apc_nc.Seats += 6 -> new SeatDefinition() - apc_nc.Seats += 7 -> new SeatDefinition() - apc_nc.Seats += 8 -> new SeatDefinition() - apc_nc.Seats += 9 -> maxOnlySeat - apc_nc.Seats += 10 -> maxOnlySeat + apc_nc.Seats += 0 -> new SeatDefinition() + apc_nc.Seats += 1 -> new SeatDefinition() + apc_nc.Seats += 2 -> new SeatDefinition() + apc_nc.Seats += 3 -> new SeatDefinition() + apc_nc.Seats += 4 -> new SeatDefinition() + apc_nc.Seats += 5 -> new SeatDefinition() + apc_nc.Seats += 6 -> new SeatDefinition() + apc_nc.Seats += 7 -> new SeatDefinition() + apc_nc.Seats += 8 -> new SeatDefinition() + apc_nc.Seats += 9 -> maxOnlySeat + apc_nc.Seats += 10 -> maxOnlySeat apc_nc.controlledWeapons += 1 -> 11 apc_nc.controlledWeapons += 2 -> 12 apc_nc.controlledWeapons += 5 -> 15 apc_nc.controlledWeapons += 6 -> 16 apc_nc.controlledWeapons += 7 -> 13 apc_nc.controlledWeapons += 8 -> 14 - apc_nc.Weapons += 11 -> apc_weapon_systemc_nc - apc_nc.Weapons += 12 -> apc_weapon_systemb - apc_nc.Weapons += 13 -> apc_weapon_systema - apc_nc.Weapons += 14 -> apc_weapon_systemd_nc - apc_nc.Weapons += 15 -> apc_ballgun_r - apc_nc.Weapons += 16 -> apc_ballgun_l - apc_nc.MountPoints += 1 -> MountInfo(0) - apc_nc.MountPoints += 2 -> MountInfo(0) - apc_nc.MountPoints += 3 -> MountInfo(1) - apc_nc.MountPoints += 4 -> MountInfo(2) - apc_nc.MountPoints += 5 -> MountInfo(3) - apc_nc.MountPoints += 6 -> MountInfo(4) - apc_nc.MountPoints += 7 -> MountInfo(5) - apc_nc.MountPoints += 8 -> MountInfo(6) - apc_nc.MountPoints += 9 -> MountInfo(7) - apc_nc.MountPoints += 10 -> MountInfo(8) - apc_nc.MountPoints += 11 -> MountInfo(9) - apc_nc.MountPoints += 12 -> MountInfo(10) + apc_nc.Weapons += 11 -> apc_weapon_systemc_nc + apc_nc.Weapons += 12 -> apc_weapon_systemb + apc_nc.Weapons += 13 -> apc_weapon_systema + apc_nc.Weapons += 14 -> apc_weapon_systemd_nc + apc_nc.Weapons += 15 -> apc_ballgun_r + apc_nc.Weapons += 16 -> apc_ballgun_l + apc_nc.MountPoints += 1 -> MountInfo(0) + apc_nc.MountPoints += 2 -> MountInfo(0) + apc_nc.MountPoints += 3 -> MountInfo(1) + apc_nc.MountPoints += 4 -> MountInfo(2) + apc_nc.MountPoints += 5 -> MountInfo(3) + apc_nc.MountPoints += 6 -> MountInfo(4) + apc_nc.MountPoints += 7 -> MountInfo(5) + apc_nc.MountPoints += 8 -> MountInfo(6) + apc_nc.MountPoints += 9 -> MountInfo(7) + apc_nc.MountPoints += 10 -> MountInfo(8) + apc_nc.MountPoints += 11 -> MountInfo(9) + apc_nc.MountPoints += 12 -> MountInfo(10) apc_nc.TrunkSize = InventoryTile.Tile2016 apc_nc.TrunkOffset = 30 apc_nc.TrunkLocation = Vector3(-5.82f, 0f, 0f) @@ -6196,41 +6204,41 @@ object GlobalDefinitions { apc_vs.Repairable = true apc_vs.RepairIfDestroyed = false apc_vs.MaxShields = 1200 - apc_vs.Seats += 0 -> new SeatDefinition() - apc_vs.Seats += 1 -> new SeatDefinition() - apc_vs.Seats += 2 -> new SeatDefinition() - apc_vs.Seats += 3 -> new SeatDefinition() - apc_vs.Seats += 4 -> new SeatDefinition() - apc_vs.Seats += 5 -> new SeatDefinition() - apc_vs.Seats += 6 -> new SeatDefinition() - apc_vs.Seats += 7 -> new SeatDefinition() - apc_vs.Seats += 8 -> new SeatDefinition() - apc_vs.Seats += 9 -> maxOnlySeat - apc_vs.Seats += 10 -> maxOnlySeat + apc_vs.Seats += 0 -> new SeatDefinition() + apc_vs.Seats += 1 -> new SeatDefinition() + apc_vs.Seats += 2 -> new SeatDefinition() + apc_vs.Seats += 3 -> new SeatDefinition() + apc_vs.Seats += 4 -> new SeatDefinition() + apc_vs.Seats += 5 -> new SeatDefinition() + apc_vs.Seats += 6 -> new SeatDefinition() + apc_vs.Seats += 7 -> new SeatDefinition() + apc_vs.Seats += 8 -> new SeatDefinition() + apc_vs.Seats += 9 -> maxOnlySeat + apc_vs.Seats += 10 -> maxOnlySeat apc_vs.controlledWeapons += 1 -> 11 apc_vs.controlledWeapons += 2 -> 12 apc_vs.controlledWeapons += 5 -> 15 apc_vs.controlledWeapons += 6 -> 16 apc_vs.controlledWeapons += 7 -> 13 apc_vs.controlledWeapons += 8 -> 14 - apc_vs.Weapons += 11 -> apc_weapon_systemc_vs - apc_vs.Weapons += 12 -> apc_weapon_systemb - apc_vs.Weapons += 13 -> apc_weapon_systema - apc_vs.Weapons += 14 -> apc_weapon_systemd_vs - apc_vs.Weapons += 15 -> apc_ballgun_r - apc_vs.Weapons += 16 -> apc_ballgun_l - apc_vs.MountPoints += 1 -> MountInfo(0) - apc_vs.MountPoints += 2 -> MountInfo(0) - apc_vs.MountPoints += 3 -> MountInfo(1) - apc_vs.MountPoints += 4 -> MountInfo(2) - apc_vs.MountPoints += 5 -> MountInfo(3) - apc_vs.MountPoints += 6 -> MountInfo(4) - apc_vs.MountPoints += 7 -> MountInfo(5) - apc_vs.MountPoints += 8 -> MountInfo(6) - apc_vs.MountPoints += 9 -> MountInfo(7) - apc_vs.MountPoints += 10 -> MountInfo(8) - apc_vs.MountPoints += 11 -> MountInfo(9) - apc_vs.MountPoints += 12 -> MountInfo(10) + apc_vs.Weapons += 11 -> apc_weapon_systemc_vs + apc_vs.Weapons += 12 -> apc_weapon_systemb + apc_vs.Weapons += 13 -> apc_weapon_systema + apc_vs.Weapons += 14 -> apc_weapon_systemd_vs + apc_vs.Weapons += 15 -> apc_ballgun_r + apc_vs.Weapons += 16 -> apc_ballgun_l + apc_vs.MountPoints += 1 -> MountInfo(0) + apc_vs.MountPoints += 2 -> MountInfo(0) + apc_vs.MountPoints += 3 -> MountInfo(1) + apc_vs.MountPoints += 4 -> MountInfo(2) + apc_vs.MountPoints += 5 -> MountInfo(3) + apc_vs.MountPoints += 6 -> MountInfo(4) + apc_vs.MountPoints += 7 -> MountInfo(5) + apc_vs.MountPoints += 8 -> MountInfo(6) + apc_vs.MountPoints += 9 -> MountInfo(7) + apc_vs.MountPoints += 10 -> MountInfo(8) + apc_vs.MountPoints += 11 -> MountInfo(9) + apc_vs.MountPoints += 12 -> MountInfo(10) apc_vs.TrunkSize = InventoryTile.Tile2016 apc_vs.TrunkOffset = 30 apc_vs.TrunkLocation = Vector3(-5.82f, 0f, 0f) @@ -6262,9 +6270,9 @@ object GlobalDefinitions { restriction = NoReinforcedOrMax } lightning.controlledWeapons += 0 -> 1 - lightning.Weapons += 1 -> lightning_weapon_system - lightning.MountPoints += 1 -> MountInfo(0) - lightning.MountPoints += 2 -> MountInfo(0) + lightning.Weapons += 1 -> lightning_weapon_system + lightning.MountPoints += 1 -> MountInfo(0) + lightning.MountPoints += 2 -> MountInfo(0) lightning.TrunkSize = InventoryTile.Tile1511 lightning.TrunkOffset = 30 lightning.TrunkLocation = Vector3(-3f, 0f, 0f) @@ -6295,15 +6303,15 @@ object GlobalDefinitions { prowler.Seats += 0 -> new SeatDefinition() { restriction = NoReinforcedOrMax } - prowler.Seats += 1 -> new SeatDefinition() - prowler.Seats += 2 -> new SeatDefinition() + prowler.Seats += 1 -> new SeatDefinition() + prowler.Seats += 2 -> new SeatDefinition() prowler.controlledWeapons += 1 -> 3 prowler.controlledWeapons += 2 -> 4 - prowler.Weapons += 3 -> prowler_weapon_systemA - prowler.Weapons += 4 -> prowler_weapon_systemB - prowler.MountPoints += 1 -> MountInfo(0) - prowler.MountPoints += 2 -> MountInfo(1) - prowler.MountPoints += 3 -> MountInfo(2) + prowler.Weapons += 3 -> prowler_weapon_systemA + prowler.Weapons += 4 -> prowler_weapon_systemB + prowler.MountPoints += 1 -> MountInfo(0) + prowler.MountPoints += 2 -> MountInfo(1) + prowler.MountPoints += 3 -> MountInfo(2) prowler.TrunkSize = InventoryTile.Tile1511 prowler.TrunkOffset = 30 prowler.TrunkLocation = Vector3(-4.71f, 0f, 0f) @@ -6334,11 +6342,11 @@ object GlobalDefinitions { vanguard.Seats += 0 -> new SeatDefinition() { restriction = NoReinforcedOrMax } - vanguard.Seats += 1 -> new SeatDefinition() + vanguard.Seats += 1 -> new SeatDefinition() vanguard.controlledWeapons += 1 -> 2 - vanguard.Weapons += 2 -> vanguard_weapon_system - vanguard.MountPoints += 1 -> MountInfo(0) - vanguard.MountPoints += 2 -> MountInfo(1) + vanguard.Weapons += 2 -> vanguard_weapon_system + vanguard.MountPoints += 1 -> MountInfo(0) + vanguard.MountPoints += 2 -> MountInfo(1) vanguard.TrunkSize = InventoryTile.Tile1511 vanguard.TrunkOffset = 30 vanguard.TrunkLocation = Vector3(-4.84f, 0f, 0f) @@ -6369,13 +6377,13 @@ object GlobalDefinitions { magrider.Seats += 0 -> new SeatDefinition() { restriction = NoReinforcedOrMax } - magrider.Seats += 1 -> new SeatDefinition() + magrider.Seats += 1 -> new SeatDefinition() magrider.controlledWeapons += 0 -> 2 magrider.controlledWeapons += 1 -> 3 - magrider.Weapons += 2 -> particle_beam_magrider - magrider.Weapons += 3 -> heavy_rail_beam_magrider - magrider.MountPoints += 1 -> MountInfo(0) - magrider.MountPoints += 2 -> MountInfo(1) + magrider.Weapons += 2 -> particle_beam_magrider + magrider.Weapons += 3 -> heavy_rail_beam_magrider + magrider.MountPoints += 1 -> MountInfo(0) + magrider.MountPoints += 2 -> MountInfo(1) magrider.TrunkSize = InventoryTile.Tile1511 magrider.TrunkOffset = 30 magrider.TrunkLocation = Vector3(5.06f, 0f, 0f) @@ -6504,7 +6512,7 @@ object GlobalDefinitions { } router.DrownAtMaxDepth = true router.MaxDepth = 2 - router.UnderwaterLifespan(suffocation = 45000L, recovery = 5000L) //but the router hovers over water, so ...? + router.UnderwaterLifespan(suffocation = 45000L, recovery = 5000L) //but the router hovers over water, so ...? router.Geometry = GeometryForm.representByCylinder(radius = 3.64845f, height = 3.51563f) //TODO hexahedron switchblade.Name = "switchblade" @@ -6513,11 +6521,11 @@ object GlobalDefinitions { switchblade.Repairable = true switchblade.RepairIfDestroyed = false switchblade.MaxShields = 350 - switchblade.Seats += 0 -> new SeatDefinition() + switchblade.Seats += 0 -> new SeatDefinition() switchblade.controlledWeapons += 0 -> 1 - switchblade.Weapons += 1 -> scythe - switchblade.MountPoints += 1 -> MountInfo(0) - switchblade.MountPoints += 2 -> MountInfo(0) + switchblade.Weapons += 1 -> scythe + switchblade.MountPoints += 1 -> MountInfo(0) + switchblade.MountPoints += 2 -> MountInfo(0) switchblade.TrunkSize = InventoryTile.Tile1511 switchblade.TrunkOffset = 30 switchblade.TrunkLocation = Vector3(-2.5f, 0f, 0f) @@ -6541,7 +6549,10 @@ object GlobalDefinitions { } switchblade.DrownAtMaxDepth = true switchblade.MaxDepth = 2 - switchblade.UnderwaterLifespan(suffocation = 45000L, recovery = 5000L) //but the switchblade hovers over water, so ...? + switchblade.UnderwaterLifespan( + suffocation = 45000L, + recovery = 5000L + ) //but the switchblade hovers over water, so ...? switchblade.Geometry = GeometryForm.representByCylinder(radius = 2.4335f, height = 2.73438f) flail.Name = "flail" @@ -6550,10 +6561,10 @@ object GlobalDefinitions { flail.Repairable = true flail.RepairIfDestroyed = false flail.MaxShields = 480 - flail.Seats += 0 -> new SeatDefinition() + flail.Seats += 0 -> new SeatDefinition() flail.controlledWeapons += 0 -> 1 - flail.Weapons += 1 -> flail_weapon - flail.MountPoints += 1 -> MountInfo(0) + flail.Weapons += 1 -> flail_weapon + flail.MountPoints += 1 -> MountInfo(0) flail.TrunkSize = InventoryTile.Tile1511 flail.TrunkOffset = 30 flail.TrunkLocation = Vector3(-3.75f, 0f, 0f) @@ -6586,11 +6597,11 @@ object GlobalDefinitions { mosquito.RepairIfDestroyed = false mosquito.MaxShields = 133 mosquito.CanFly = true - mosquito.Seats += 0 -> bailableSeat + mosquito.Seats += 0 -> bailableSeat mosquito.controlledWeapons += 0 -> 1 - mosquito.Weapons += 1 -> rotarychaingun_mosquito - mosquito.MountPoints += 1 -> MountInfo(0) - mosquito.MountPoints += 2 -> MountInfo(0) + mosquito.Weapons += 1 -> rotarychaingun_mosquito + mosquito.MountPoints += 1 -> MountInfo(0) + mosquito.MountPoints += 2 -> MountInfo(0) mosquito.TrunkSize = InventoryTile.Tile1111 mosquito.TrunkOffset = 30 mosquito.TrunkLocation = Vector3(-4.6f, 0f, 0f) @@ -6619,11 +6630,11 @@ object GlobalDefinitions { lightgunship.RepairIfDestroyed = false lightgunship.MaxShields = 200 lightgunship.CanFly = true - lightgunship.Seats += 0 -> bailableSeat + lightgunship.Seats += 0 -> bailableSeat lightgunship.controlledWeapons += 0 -> 1 - lightgunship.Weapons += 1 -> lightgunship_weapon_system - lightgunship.MountPoints += 1 -> MountInfo(0) - lightgunship.MountPoints += 2 -> MountInfo(0) + lightgunship.Weapons += 1 -> lightgunship_weapon_system + lightgunship.MountPoints += 1 -> MountInfo(0) + lightgunship.MountPoints += 2 -> MountInfo(0) lightgunship.TrunkSize = InventoryTile.Tile1511 lightgunship.TrunkOffset = 30 lightgunship.TrunkLocation = Vector3(-5.61f, 0f, 0f) @@ -6653,11 +6664,11 @@ object GlobalDefinitions { wasp.RepairIfDestroyed = false wasp.MaxShields = 103 wasp.CanFly = true - wasp.Seats += 0 -> bailableSeat + wasp.Seats += 0 -> bailableSeat wasp.controlledWeapons += 0 -> 1 - wasp.Weapons += 1 -> wasp_weapon_system - wasp.MountPoints += 1 -> MountInfo(0) - wasp.MountPoints += 2 -> MountInfo(0) + wasp.Weapons += 1 -> wasp_weapon_system + wasp.MountPoints += 1 -> MountInfo(0) + wasp.MountPoints += 2 -> MountInfo(0) wasp.TrunkSize = InventoryTile.Tile1111 wasp.TrunkOffset = 30 wasp.TrunkLocation = Vector3(-4.6f, 0f, 0f) @@ -6686,19 +6697,19 @@ object GlobalDefinitions { liberator.RepairIfDestroyed = false liberator.MaxShields = 500 liberator.CanFly = true - liberator.Seats += 0 -> new SeatDefinition() - liberator.Seats += 1 -> bailableSeat - liberator.Seats += 2 -> bailableSeat + liberator.Seats += 0 -> new SeatDefinition() + liberator.Seats += 1 -> bailableSeat + liberator.Seats += 2 -> bailableSeat liberator.controlledWeapons += 0 -> 3 liberator.controlledWeapons += 1 -> 4 liberator.controlledWeapons += 2 -> 5 - liberator.Weapons += 3 -> liberator_weapon_system - liberator.Weapons += 4 -> liberator_bomb_bay - liberator.Weapons += 5 -> liberator_25mm_cannon - liberator.MountPoints += 1 -> MountInfo(0) - liberator.MountPoints += 2 -> MountInfo(1) - liberator.MountPoints += 3 -> MountInfo(1) - liberator.MountPoints += 4 -> MountInfo(2) + liberator.Weapons += 3 -> liberator_weapon_system + liberator.Weapons += 4 -> liberator_bomb_bay + liberator.Weapons += 5 -> liberator_25mm_cannon + liberator.MountPoints += 1 -> MountInfo(0) + liberator.MountPoints += 2 -> MountInfo(1) + liberator.MountPoints += 3 -> MountInfo(1) + liberator.MountPoints += 4 -> MountInfo(2) liberator.TrunkSize = InventoryTile.Tile1515 liberator.TrunkOffset = 30 liberator.TrunkLocation = Vector3(-0.76f, -1.88f, 0f) @@ -6728,19 +6739,19 @@ object GlobalDefinitions { vulture.RepairIfDestroyed = false vulture.MaxShields = 500 vulture.CanFly = true - vulture.Seats += 0 -> new SeatDefinition() - vulture.Seats += 1 -> bailableSeat - vulture.Seats += 2 -> bailableSeat + vulture.Seats += 0 -> new SeatDefinition() + vulture.Seats += 1 -> bailableSeat + vulture.Seats += 2 -> bailableSeat vulture.controlledWeapons += 0 -> 3 vulture.controlledWeapons += 1 -> 4 vulture.controlledWeapons += 2 -> 5 - vulture.Weapons += 3 -> vulture_nose_weapon_system - vulture.Weapons += 4 -> vulture_bomb_bay - vulture.Weapons += 5 -> vulture_tail_cannon - vulture.MountPoints += 1 -> MountInfo(0) - vulture.MountPoints += 2 -> MountInfo(1) - vulture.MountPoints += 3 -> MountInfo(1) - vulture.MountPoints += 4 -> MountInfo(2) + vulture.Weapons += 3 -> vulture_nose_weapon_system + vulture.Weapons += 4 -> vulture_bomb_bay + vulture.Weapons += 5 -> vulture_tail_cannon + vulture.MountPoints += 1 -> MountInfo(0) + vulture.MountPoints += 2 -> MountInfo(1) + vulture.MountPoints += 3 -> MountInfo(1) + vulture.MountPoints += 4 -> MountInfo(2) vulture.TrunkSize = InventoryTile.Tile1611 vulture.TrunkOffset = 30 vulture.TrunkLocation = Vector3(-0.76f, -1.88f, 0f) @@ -6790,25 +6801,25 @@ object GlobalDefinitions { bailable = true restriction = MaxOnly } - dropship.Seats += 11 -> bailableSeat - dropship.controlledWeapons += 1 -> 12 - dropship.controlledWeapons += 2 -> 13 + dropship.Seats += 11 -> bailableSeat + dropship.controlledWeapons += 1 -> 12 + dropship.controlledWeapons += 2 -> 13 dropship.controlledWeapons += 11 -> 14 - dropship.Weapons += 12 -> cannon_dropship_20mm - dropship.Weapons += 13 -> cannon_dropship_20mm - dropship.Weapons += 14 -> dropship_rear_turret - dropship.Cargo += 15 -> new CargoDefinition() { + dropship.Weapons += 12 -> cannon_dropship_20mm + dropship.Weapons += 13 -> cannon_dropship_20mm + dropship.Weapons += 14 -> dropship_rear_turret + dropship.Cargo += 15 -> new CargoDefinition() { restriction = SmallCargo } - dropship.MountPoints += 1 -> MountInfo(0) - dropship.MountPoints += 2 -> MountInfo(11) - dropship.MountPoints += 3 -> MountInfo(1) - dropship.MountPoints += 4 -> MountInfo(2) - dropship.MountPoints += 5 -> MountInfo(3) - dropship.MountPoints += 6 -> MountInfo(4) - dropship.MountPoints += 7 -> MountInfo(5) - dropship.MountPoints += 8 -> MountInfo(6) - dropship.MountPoints += 9 -> MountInfo(7) + dropship.MountPoints += 1 -> MountInfo(0) + dropship.MountPoints += 2 -> MountInfo(11) + dropship.MountPoints += 3 -> MountInfo(1) + dropship.MountPoints += 4 -> MountInfo(2) + dropship.MountPoints += 5 -> MountInfo(3) + dropship.MountPoints += 6 -> MountInfo(4) + dropship.MountPoints += 7 -> MountInfo(5) + dropship.MountPoints += 8 -> MountInfo(6) + dropship.MountPoints += 9 -> MountInfo(7) dropship.MountPoints += 10 -> MountInfo(8) dropship.MountPoints += 11 -> MountInfo(9) dropship.MountPoints += 12 -> MountInfo(10) @@ -6843,28 +6854,28 @@ object GlobalDefinitions { galaxy_gunship.RepairIfDestroyed = false galaxy_gunship.MaxShields = 1200 galaxy_gunship.CanFly = true - galaxy_gunship.Seats += 0 -> new SeatDefinition() - galaxy_gunship.Seats += 1 -> bailableSeat - galaxy_gunship.Seats += 2 -> bailableSeat - galaxy_gunship.Seats += 3 -> bailableSeat - galaxy_gunship.Seats += 4 -> bailableSeat - galaxy_gunship.Seats += 5 -> bailableSeat + galaxy_gunship.Seats += 0 -> new SeatDefinition() + galaxy_gunship.Seats += 1 -> bailableSeat + galaxy_gunship.Seats += 2 -> bailableSeat + galaxy_gunship.Seats += 3 -> bailableSeat + galaxy_gunship.Seats += 4 -> bailableSeat + galaxy_gunship.Seats += 5 -> bailableSeat galaxy_gunship.controlledWeapons += 1 -> 6 galaxy_gunship.controlledWeapons += 2 -> 7 galaxy_gunship.controlledWeapons += 3 -> 8 galaxy_gunship.controlledWeapons += 4 -> 9 galaxy_gunship.controlledWeapons += 5 -> 10 - galaxy_gunship.Weapons += 6 -> galaxy_gunship_cannon - galaxy_gunship.Weapons += 7 -> galaxy_gunship_cannon - galaxy_gunship.Weapons += 8 -> galaxy_gunship_tailgun - galaxy_gunship.Weapons += 9 -> galaxy_gunship_gun - galaxy_gunship.Weapons += 10 -> galaxy_gunship_gun - galaxy_gunship.MountPoints += 1 -> MountInfo(0) - galaxy_gunship.MountPoints += 2 -> MountInfo(3) - galaxy_gunship.MountPoints += 3 -> MountInfo(1) - galaxy_gunship.MountPoints += 4 -> MountInfo(2) - galaxy_gunship.MountPoints += 5 -> MountInfo(4) - galaxy_gunship.MountPoints += 6 -> MountInfo(5) + galaxy_gunship.Weapons += 6 -> galaxy_gunship_cannon + galaxy_gunship.Weapons += 7 -> galaxy_gunship_cannon + galaxy_gunship.Weapons += 8 -> galaxy_gunship_tailgun + galaxy_gunship.Weapons += 9 -> galaxy_gunship_gun + galaxy_gunship.Weapons += 10 -> galaxy_gunship_gun + galaxy_gunship.MountPoints += 1 -> MountInfo(0) + galaxy_gunship.MountPoints += 2 -> MountInfo(3) + galaxy_gunship.MountPoints += 3 -> MountInfo(1) + galaxy_gunship.MountPoints += 4 -> MountInfo(2) + galaxy_gunship.MountPoints += 5 -> MountInfo(4) + galaxy_gunship.MountPoints += 6 -> MountInfo(5) galaxy_gunship.TrunkSize = InventoryTile.Tile1816 galaxy_gunship.TrunkOffset = 30 galaxy_gunship.TrunkLocation = Vector3(-9.85f, 0f, 0f) @@ -6898,8 +6909,8 @@ object GlobalDefinitions { lodestar.MaxShields = 1000 lodestar.CanFly = true lodestar.Seats += 0 -> new SeatDefinition() - lodestar.MountPoints += 1 -> MountInfo(0) - lodestar.MountPoints += 2 -> MountInfo(1) + lodestar.MountPoints += 1 -> MountInfo(0) + lodestar.MountPoints += 2 -> MountInfo(1) lodestar.Cargo += 1 -> new CargoDefinition() lodestar.Utilities += 2 -> UtilityType.lodestar_repair_terminal lodestar.UtilityOffset += 2 -> Vector3(0, 20, 0) @@ -6939,11 +6950,11 @@ object GlobalDefinitions { phantasm.MaxShields = 500 phantasm.CanCloak = true phantasm.CanFly = true - phantasm.Seats += 0 -> new SeatDefinition() - phantasm.Seats += 1 -> bailableSeat - phantasm.Seats += 2 -> bailableSeat - phantasm.Seats += 3 -> bailableSeat - phantasm.Seats += 4 -> bailableSeat + phantasm.Seats += 0 -> new SeatDefinition() + phantasm.Seats += 1 -> bailableSeat + phantasm.Seats += 2 -> bailableSeat + phantasm.Seats += 3 -> bailableSeat + phantasm.Seats += 4 -> bailableSeat phantasm.MountPoints += 1 -> MountInfo(0) phantasm.MountPoints += 2 -> MountInfo(1) phantasm.MountPoints += 3 -> MountInfo(2) @@ -7002,15 +7013,15 @@ object GlobalDefinitions { physically, they correlate to positions in the HART building rather than with the shuttle model by itself; set the shuttle pad based on the zonemap extraction values then position the shuttle relative to that pad; rotation based on the shuttle should place these offsets in the HART lobby whose gantry hall corresponds to that mount index - */ - orbital_shuttle.MountPoints += 1 -> MountInfo(0, Vector3(-62, 4, -28.2f)) + */ + orbital_shuttle.MountPoints += 1 -> MountInfo(0, Vector3(-62, 4, -28.2f)) orbital_shuttle.MountPoints += 2 -> MountInfo(0, Vector3(-62, 28, -28.2f)) - orbital_shuttle.MountPoints += 3 -> MountInfo(0, Vector3(-62, 4, -18.2f)) + orbital_shuttle.MountPoints += 3 -> MountInfo(0, Vector3(-62, 4, -18.2f)) orbital_shuttle.MountPoints += 4 -> MountInfo(0, Vector3(-62, 28, -18.2f)) - orbital_shuttle.MountPoints += 5 -> MountInfo(0, Vector3( 62, 4, -28.2f)) - orbital_shuttle.MountPoints += 6 -> MountInfo(0, Vector3( 62, 28, -28.2f)) - orbital_shuttle.MountPoints += 7 -> MountInfo(0, Vector3( 62, 4, -18.2f)) - orbital_shuttle.MountPoints += 8 -> MountInfo(0, Vector3( 62, 28, -18.2f)) + orbital_shuttle.MountPoints += 5 -> MountInfo(0, Vector3(62, 4, -28.2f)) + orbital_shuttle.MountPoints += 6 -> MountInfo(0, Vector3(62, 28, -28.2f)) + orbital_shuttle.MountPoints += 7 -> MountInfo(0, Vector3(62, 4, -18.2f)) + orbital_shuttle.MountPoints += 8 -> MountInfo(0, Vector3(62, 28, -18.2f)) orbital_shuttle.TrunkSize = InventoryTile.None orbital_shuttle.Packet = new OrbitalShuttleConverter orbital_shuttle.DeconstructionTime = None @@ -7023,9 +7034,9 @@ object GlobalDefinitions { * Initialize `Deployable` globals. */ private def init_deployables(): Unit = { - val mine = GeometryForm.representByCylinder(radius = 0.1914f, height = 0.0957f) _ + val mine = GeometryForm.representByCylinder(radius = 0.1914f, height = 0.0957f) _ val smallTurret = GeometryForm.representByCylinder(radius = 0.48435f, height = 1.23438f) _ - val sensor = GeometryForm.representByCylinder(radius = 0.1914f, height = 1.21875f) _ + val sensor = GeometryForm.representByCylinder(radius = 0.1914f, height = 1.21875f) _ val largeTurret = GeometryForm.representByCylinder(radius = 0.8437f, height = 2.29687f) _ boomer.Name = "boomer" @@ -7197,11 +7208,11 @@ object GlobalDefinitions { portable_manned_turret.Damageable = true portable_manned_turret.Repairable = true portable_manned_turret.RepairIfDestroyed = false - portable_manned_turret.controlledWeapons += 0 -> 1 + portable_manned_turret.controlledWeapons += 0 -> 1 portable_manned_turret.WeaponPaths += 1 -> new mutable.HashMap() portable_manned_turret.WeaponPaths(1) += TurretUpgrade.None -> energy_gun - portable_manned_turret.MountPoints += 1 -> MountInfo(0) - portable_manned_turret.MountPoints += 2 -> MountInfo(0) + portable_manned_turret.MountPoints += 1 -> MountInfo(0) + portable_manned_turret.MountPoints += 2 -> MountInfo(0) portable_manned_turret.ReserveAmmunition = true portable_manned_turret.FactionLocked = true portable_manned_turret.Packet = fieldTurretConverter @@ -7227,9 +7238,9 @@ object GlobalDefinitions { portable_manned_turret_nc.RepairIfDestroyed = false portable_manned_turret_nc.WeaponPaths += 1 -> new mutable.HashMap() portable_manned_turret_nc.WeaponPaths(1) += TurretUpgrade.None -> energy_gun_nc - portable_manned_turret_nc.controlledWeapons += 0 -> 1 - portable_manned_turret_nc.MountPoints += 1 -> MountInfo(0) - portable_manned_turret_nc.MountPoints += 2 -> MountInfo(0) + portable_manned_turret_nc.controlledWeapons += 0 -> 1 + portable_manned_turret_nc.MountPoints += 1 -> MountInfo(0) + portable_manned_turret_nc.MountPoints += 2 -> MountInfo(0) portable_manned_turret_nc.ReserveAmmunition = true portable_manned_turret_nc.FactionLocked = true portable_manned_turret_nc.Packet = fieldTurretConverter @@ -7255,9 +7266,9 @@ object GlobalDefinitions { portable_manned_turret_tr.RepairIfDestroyed = false portable_manned_turret_tr.WeaponPaths += 1 -> new mutable.HashMap() portable_manned_turret_tr.WeaponPaths(1) += TurretUpgrade.None -> energy_gun_tr - portable_manned_turret_tr.controlledWeapons += 0 -> 1 - portable_manned_turret_tr.MountPoints += 1 -> MountInfo(0) - portable_manned_turret_tr.MountPoints += 2 -> MountInfo(0) + portable_manned_turret_tr.controlledWeapons += 0 -> 1 + portable_manned_turret_tr.MountPoints += 1 -> MountInfo(0) + portable_manned_turret_tr.MountPoints += 2 -> MountInfo(0) portable_manned_turret_tr.ReserveAmmunition = true portable_manned_turret_tr.FactionLocked = true portable_manned_turret_tr.Packet = fieldTurretConverter @@ -7283,9 +7294,9 @@ object GlobalDefinitions { portable_manned_turret_vs.RepairIfDestroyed = false portable_manned_turret_vs.WeaponPaths += 1 -> new mutable.HashMap() portable_manned_turret_vs.WeaponPaths(1) += TurretUpgrade.None -> energy_gun_vs - portable_manned_turret_vs.controlledWeapons += 0 -> 1 - portable_manned_turret_vs.MountPoints += 1 -> MountInfo(0) - portable_manned_turret_vs.MountPoints += 2 -> MountInfo(0) + portable_manned_turret_vs.controlledWeapons += 0 -> 1 + portable_manned_turret_vs.MountPoints += 1 -> MountInfo(0) + portable_manned_turret_vs.MountPoints += 2 -> MountInfo(0) portable_manned_turret_vs.ReserveAmmunition = true portable_manned_turret_vs.FactionLocked = true portable_manned_turret_vs.Packet = fieldTurretConverter @@ -7394,7 +7405,7 @@ object GlobalDefinitions { order_terminal.MaxHealth = 500 order_terminal.Damageable = true order_terminal.Repairable = true - order_terminal.autoRepair = AutoRepairStats(2.24215f, 5000, 3500, 0.5f) + order_terminal.autoRepair = AutoRepairStats(2.24215f, 5000, 3500, 0.5f) order_terminal.RepairIfDestroyed = true order_terminal.Subtract.Damage1 = 8 order_terminal.Geometry = GeometryForm.representByCylinder(radius = 0.8438f, height = 1.3f) @@ -7459,7 +7470,7 @@ object GlobalDefinitions { cert_terminal.MaxHealth = 500 cert_terminal.Damageable = true cert_terminal.Repairable = true - cert_terminal.autoRepair = AutoRepairStats(2.24215f, 5000, 3500, 0.5f) + cert_terminal.autoRepair = AutoRepairStats(2.24215f, 5000, 3500, 0.5f) cert_terminal.RepairIfDestroyed = true cert_terminal.Subtract.Damage1 = 8 cert_terminal.Geometry = GeometryForm.representByCylinder(radius = 0.66405f, height = 1.09374f) @@ -7477,7 +7488,8 @@ object GlobalDefinitions { implant_terminal_interface.MaxHealth = 500 implant_terminal_interface.Damageable = false //TODO true implant_terminal_interface.Repairable = true - implant_terminal_interface.autoRepair = AutoRepairStats(1, 5000, 200, 1) //TODO amount and drain are default? undefined? + implant_terminal_interface.autoRepair = + AutoRepairStats(1, 5000, 200, 1) //TODO amount and drain are default? undefined? implant_terminal_interface.RepairIfDestroyed = true //TODO will need geometry when Damageable = true @@ -7490,7 +7502,7 @@ object GlobalDefinitions { ground_vehicle_terminal.MaxHealth = 500 ground_vehicle_terminal.Damageable = true ground_vehicle_terminal.Repairable = true - ground_vehicle_terminal.autoRepair = AutoRepairStats(2.24215f, 5000, 3500, 0.5f) + ground_vehicle_terminal.autoRepair = AutoRepairStats(2.24215f, 5000, 3500, 0.5f) ground_vehicle_terminal.RepairIfDestroyed = true ground_vehicle_terminal.Subtract.Damage1 = 8 ground_vehicle_terminal.Geometry = vterm @@ -7504,7 +7516,7 @@ object GlobalDefinitions { air_vehicle_terminal.MaxHealth = 500 air_vehicle_terminal.Damageable = true air_vehicle_terminal.Repairable = true - air_vehicle_terminal.autoRepair = AutoRepairStats(2.24215f, 5000, 3500, 0.5f) + air_vehicle_terminal.autoRepair = AutoRepairStats(2.24215f, 5000, 3500, 0.5f) air_vehicle_terminal.RepairIfDestroyed = true air_vehicle_terminal.Subtract.Damage1 = 8 air_vehicle_terminal.Geometry = vterm @@ -7518,7 +7530,7 @@ object GlobalDefinitions { dropship_vehicle_terminal.MaxHealth = 500 dropship_vehicle_terminal.Damageable = true dropship_vehicle_terminal.Repairable = true - dropship_vehicle_terminal.autoRepair = AutoRepairStats(2.24215f, 5000, 3500, 0.5f) + dropship_vehicle_terminal.autoRepair = AutoRepairStats(2.24215f, 5000, 3500, 0.5f) dropship_vehicle_terminal.RepairIfDestroyed = true dropship_vehicle_terminal.Subtract.Damage1 = 8 dropship_vehicle_terminal.Geometry = vterm @@ -7532,7 +7544,7 @@ object GlobalDefinitions { vehicle_terminal_combined.MaxHealth = 500 vehicle_terminal_combined.Damageable = true vehicle_terminal_combined.Repairable = true - vehicle_terminal_combined.autoRepair = AutoRepairStats(2.24215f, 5000, 3500, 0.5f) + vehicle_terminal_combined.autoRepair = AutoRepairStats(2.24215f, 5000, 3500, 0.5f) vehicle_terminal_combined.RepairIfDestroyed = true vehicle_terminal_combined.Subtract.Damage1 = 8 vehicle_terminal_combined.Geometry = vterm @@ -7546,7 +7558,7 @@ object GlobalDefinitions { vanu_air_vehicle_term.MaxHealth = 500 vanu_air_vehicle_term.Damageable = true vanu_air_vehicle_term.Repairable = true - vanu_air_vehicle_term.autoRepair = AutoRepairStats(2.24215f, 5000, 3500, 0.5f) + vanu_air_vehicle_term.autoRepair = AutoRepairStats(2.24215f, 5000, 3500, 0.5f) vanu_air_vehicle_term.RepairIfDestroyed = true vanu_air_vehicle_term.Subtract.Damage1 = 8 @@ -7559,7 +7571,7 @@ object GlobalDefinitions { vanu_vehicle_term.MaxHealth = 500 vanu_vehicle_term.Damageable = true vanu_vehicle_term.Repairable = true - vanu_vehicle_term.autoRepair = AutoRepairStats(2.24215f, 5000, 3500, 0.5f) + vanu_vehicle_term.autoRepair = AutoRepairStats(2.24215f, 5000, 3500, 0.5f) vanu_vehicle_term.RepairIfDestroyed = true vanu_vehicle_term.Subtract.Damage1 = 8 @@ -7572,7 +7584,7 @@ object GlobalDefinitions { bfr_terminal.MaxHealth = 500 bfr_terminal.Damageable = true bfr_terminal.Repairable = true - bfr_terminal.autoRepair = AutoRepairStats(2.24215f, 5000, 3500, 0.5f) + bfr_terminal.autoRepair = AutoRepairStats(2.24215f, 5000, 3500, 0.5f) bfr_terminal.RepairIfDestroyed = true bfr_terminal.Subtract.Damage1 = 8 bfr_terminal.Geometry = GeometryForm.representByCylinder(radius = 0.92185f, height = 2.64693f) @@ -7584,7 +7596,7 @@ object GlobalDefinitions { respawn_tube.Damageable = true respawn_tube.DamageableByFriendlyFire = false respawn_tube.Repairable = true - respawn_tube.autoRepair = AutoRepairStats(1.6f, 10000, 2400, 1) + respawn_tube.autoRepair = AutoRepairStats(1.6f, 10000, 2400, 1) respawn_tube.RepairIfDestroyed = true respawn_tube.Subtract.Damage1 = 8 respawn_tube.Geometry = GeometryForm.representByCylinder(radius = 0.9336f, height = 2.84375f) @@ -7606,7 +7618,7 @@ object GlobalDefinitions { respawn_tube_tower.Damageable = true respawn_tube_tower.DamageableByFriendlyFire = false respawn_tube_tower.Repairable = true - respawn_tube_tower.autoRepair = AutoRepairStats(1.6f, 10000, 2400, 1) + respawn_tube_tower.autoRepair = AutoRepairStats(1.6f, 10000, 2400, 1) respawn_tube_tower.RepairIfDestroyed = true respawn_tube_tower.Subtract.Damage1 = 8 respawn_tube_tower.Geometry = GeometryForm.representByCylinder(radius = 0.9336f, height = 2.84375f) @@ -7625,7 +7637,7 @@ object GlobalDefinitions { medical_terminal.MaxHealth = 500 medical_terminal.Damageable = true medical_terminal.Repairable = true - medical_terminal.autoRepair = AutoRepairStats(2.24215f, 5000, 3500, 0.5f) + medical_terminal.autoRepair = AutoRepairStats(2.24215f, 5000, 3500, 0.5f) medical_terminal.RepairIfDestroyed = true medical_terminal.Geometry = GeometryForm.representByCylinder(radius = 0.711f, height = 1.75f) @@ -7638,7 +7650,7 @@ object GlobalDefinitions { adv_med_terminal.MaxHealth = 750 adv_med_terminal.Damageable = true adv_med_terminal.Repairable = true - adv_med_terminal.autoRepair = AutoRepairStats(1.57894f, 5000, 2400, 0.5f) + adv_med_terminal.autoRepair = AutoRepairStats(1.57894f, 5000, 2400, 0.5f) adv_med_terminal.RepairIfDestroyed = true adv_med_terminal.Geometry = GeometryForm.representByCylinder(radius = 0.8662125f, height = 3.47f) @@ -7667,7 +7679,7 @@ object GlobalDefinitions { portable_med_terminal.MaxHealth = 500 portable_med_terminal.Damageable = false //TODO actually true portable_med_terminal.Repairable = false - portable_med_terminal.autoRepair = AutoRepairStats(2.24215f, 5000, 3500, 0.5f) + portable_med_terminal.autoRepair = AutoRepairStats(2.24215f, 5000, 3500, 0.5f) pad_landing_frame.Name = "pad_landing_frame" pad_landing_frame.Interval = 1000 @@ -7785,14 +7797,14 @@ object GlobalDefinitions { manned_turret.Damageable = true manned_turret.DamageDisablesAt = 0 manned_turret.Repairable = true - manned_turret.autoRepair = AutoRepairStats(1.0909f, 10000, 1600, 0.5f) + manned_turret.autoRepair = AutoRepairStats(1.0909f, 10000, 1600, 0.5f) manned_turret.RepairIfDestroyed = true manned_turret.WeaponPaths += 1 -> new mutable.HashMap() manned_turret.WeaponPaths(1) += TurretUpgrade.None -> phalanx_sgl_hevgatcan manned_turret.WeaponPaths(1) += TurretUpgrade.AVCombo -> phalanx_avcombo manned_turret.WeaponPaths(1) += TurretUpgrade.FlakCombo -> phalanx_flakcombo - manned_turret.controlledWeapons += 0 -> 1 - manned_turret.MountPoints += 1 -> MountInfo(0) + manned_turret.controlledWeapons += 0 -> 1 + manned_turret.MountPoints += 1 -> MountInfo(0) manned_turret.FactionLocked = true manned_turret.ReserveAmmunition = false manned_turret.explodes = true @@ -7811,13 +7823,13 @@ object GlobalDefinitions { vanu_sentry_turret.Damageable = true vanu_sentry_turret.DamageDisablesAt = 0 vanu_sentry_turret.Repairable = true - vanu_sentry_turret.autoRepair = AutoRepairStats(3.27272f, 10000, 1000, 0.5f) + vanu_sentry_turret.autoRepair = AutoRepairStats(3.27272f, 10000, 1000, 0.5f) vanu_sentry_turret.RepairIfDestroyed = true vanu_sentry_turret.WeaponPaths += 1 -> new mutable.HashMap() vanu_sentry_turret.WeaponPaths(1) += TurretUpgrade.None -> vanu_sentry_turret_weapon - vanu_sentry_turret.controlledWeapons += 0 -> 1 - vanu_sentry_turret.MountPoints += 1 -> MountInfo(0) - vanu_sentry_turret.MountPoints += 2 -> MountInfo(0) + vanu_sentry_turret.controlledWeapons += 0 -> 1 + vanu_sentry_turret.MountPoints += 1 -> MountInfo(0) + vanu_sentry_turret.MountPoints += 2 -> MountInfo(0) vanu_sentry_turret.FactionLocked = false vanu_sentry_turret.ReserveAmmunition = false vanu_sentry_turret.Geometry = GeometryForm.representByCylinder(radius = 1.76311f, height = 3.984375f) @@ -7895,7 +7907,7 @@ object GlobalDefinitions { generator.Damageable = true generator.DamageableByFriendlyFire = false generator.Repairable = true - generator.autoRepair = AutoRepairStats(0.77775f, 5000, 875, 1) + generator.autoRepair = AutoRepairStats(0.77775f, 5000, 875, 1) generator.RepairDistance = 13.5f generator.RepairIfDestroyed = true generator.Subtract.Damage1 = 9 From f2953890be6b38a46099bbebd0a5bdf5244225d4 Mon Sep 17 00:00:00 2001 From: Jakob Gillich Date: Sat, 17 Apr 2021 02:12:26 +0200 Subject: [PATCH 05/13] Log packet contents when no decoder is found --- .../packet/ControlPacketOpcode.scala | 2 +- .../psforever/packet/GamePacketOpcode.scala | 482 +++++++++--------- 2 files changed, 242 insertions(+), 242 deletions(-) diff --git a/src/main/scala/net/psforever/packet/ControlPacketOpcode.scala b/src/main/scala/net/psforever/packet/ControlPacketOpcode.scala index 0e3d5985..c53e1624 100644 --- a/src/main/scala/net/psforever/packet/ControlPacketOpcode.scala +++ b/src/main/scala/net/psforever/packet/ControlPacketOpcode.scala @@ -28,7 +28,7 @@ object ControlPacketOpcode extends Enumeration { Unknown26, Unknown27, Unknown28, ConnectionClose, Unknown30 = Value private def noDecoder(opcode: ControlPacketOpcode.Type) = - (_: BitVector) => Attempt.failure(Err(s"Could not find a marshaller for control packet $opcode")) + (bits: BitVector) => Attempt.failure(Err(s"Could not find a marshaller for control packet $opcode (${bits.toHex})")) def getPacketDecoder( opcode: ControlPacketOpcode.Type diff --git a/src/main/scala/net/psforever/packet/GamePacketOpcode.scala b/src/main/scala/net/psforever/packet/GamePacketOpcode.scala index 6b93a923..1cc5d89c 100644 --- a/src/main/scala/net/psforever/packet/GamePacketOpcode.scala +++ b/src/main/scala/net/psforever/packet/GamePacketOpcode.scala @@ -18,284 +18,284 @@ object GamePacketOpcode extends Enumeration { type Type = Value val // OPCODES 0x00-0f - Unknown0, // PPT_NULL in beta client - LoginMessage, - LoginRespMessage, + Unknown0, // PPT_NULL in beta client + LoginMessage, // + LoginRespMessage, // ConnectToWorldRequestMessage, // found by searching for 83 F8 03 89 in IDA - ConnectToWorldMessage, - VNLWorldStatusMessage, - UnknownMessage6, // PPT_TRANSFERTOWORLDREQUEST - UnknownMessage7, // PPT_TRANSFERTOWORLDRESPONSE + ConnectToWorldMessage, // + VNLWorldStatusMessage, // + UnknownMessage6, // PPT_TRANSFERTOWORLDREQUEST + UnknownMessage7, // PPT_TRANSFERTOWORLDRESPONSE // 0x08 - PlayerStateMessage, - HitMessage, - HitHint, - DamageMessage, - DestroyMessage, - ReloadMessage, - MountVehicleMsg, - DismountVehicleMsg, + PlayerStateMessage, // + HitMessage, // + HitHint, // + DamageMessage, // + DestroyMessage, // + ReloadMessage, // + MountVehicleMsg, // + DismountVehicleMsg, // // OPCODES 0x10-1f - UseItemMessage, - MoveItemMessage, - ChatMsg, - CharacterNoRecordMessage, - CharacterInfoMessage, - UnknownMessage21, // PPT_DISCONNECT - BindPlayerMessage, + UseItemMessage, // + MoveItemMessage, // + ChatMsg, // + CharacterNoRecordMessage, // + CharacterInfoMessage, // + UnknownMessage21, // PPT_DISCONNECT + BindPlayerMessage, // ObjectCreateMessage_Duplicate, // PPT_OBJECTCREATE // 0x18 - ObjectCreateMessage, // PPT_OBJECTCREATEDETAILED - ObjectDeleteMessage, - PingMsg, - VehicleStateMessage, - FrameVehicleStateMessage, - GenericObjectStateMsg, - ChildObjectStateMessage, - ActionResultMessage, + ObjectCreateMessage, // PPT_OBJECTCREATEDETAILED + ObjectDeleteMessage, // + PingMsg, // + VehicleStateMessage, // + FrameVehicleStateMessage, // + GenericObjectStateMsg, // + ChildObjectStateMessage, // + ActionResultMessage, // // OPCODES 0x20-2f - UnknownMessage32, // PPT_ACTIONBEGIN - ActionProgressMessage, - ActionCancelMessage, - ActionCancelAcknowledgeMessage, - SetEmpireMessage, - EmoteMsg, - UnuseItemMessage, - ObjectDetachMessage, + UnknownMessage32, // PPT_ACTIONBEGIN + ActionProgressMessage, // + ActionCancelMessage, // + ActionCancelAcknowledgeMessage, // + SetEmpireMessage, // + EmoteMsg, // + UnuseItemMessage, // + ObjectDetachMessage, // // 0x28 - CreateShortcutMessage, - ChangeShortcutBankMessage, - ObjectAttachMessage, - UnknownMessage43, // PPT_OBJECTEMPTY - PlanetsideAttributeMessage, - RequestDestroyMessage, - UnknownMessage46, // PPT_EQUIPITEM - CharacterCreateRequestMessage, + CreateShortcutMessage, // + ChangeShortcutBankMessage, // + ObjectAttachMessage, // + UnknownMessage43, // PPT_OBJECTEMPTY + PlanetsideAttributeMessage, // + RequestDestroyMessage, // + UnknownMessage46, // PPT_EQUIPITEM + CharacterCreateRequestMessage, // // OPCODES 0x30-3f - CharacterRequestMessage, - LoadMapMessage, - SetCurrentAvatarMessage, - ObjectHeldMessage, - WeaponFireMessage, - AvatarJumpMessage, - PickupItemMessage, - DropItemMessage, + CharacterRequestMessage, // + LoadMapMessage, // + SetCurrentAvatarMessage, // + ObjectHeldMessage, // + WeaponFireMessage, // + AvatarJumpMessage, // + PickupItemMessage, // + DropItemMessage, // // 0x38 - InventoryStateMessage, - ChangeFireStateMessage_Start, - ChangeFireStateMessage_Stop, - UnknownMessage59, - GenericCollisionMsg, - QuantityUpdateMessage, - ArmorChangedMessage, - ProjectileStateMessage, + InventoryStateMessage, // + ChangeFireStateMessage_Start, // + ChangeFireStateMessage_Stop, // + UnknownMessage59, // + GenericCollisionMsg, // + QuantityUpdateMessage, // + ArmorChangedMessage, // + ProjectileStateMessage, // // OPCODES 0x40-4f - MountVehicleCargoMsg, - DismountVehicleCargoMsg, - CargoMountPointStatusMessage, - BeginZoningMessage, - ItemTransactionMessage, - ItemTransactionResultMessage, - ChangeFireModeMessage, - ChangeAmmoMessage, + MountVehicleCargoMsg, // + DismountVehicleCargoMsg, // + CargoMountPointStatusMessage, // + BeginZoningMessage, // + ItemTransactionMessage, // + ItemTransactionResultMessage, // + ChangeFireModeMessage, // + ChangeAmmoMessage, // // 0x48 - TimeOfDayMessage, - UnknownMessage73, // PPT_PROJECTILE_EVENT_BLOCK - SpawnRequestMessage, - DeployRequestMessage, - UnknownMessage76, // PPT_BUILDINGSTATECHANGED - RepairMessage, - ServerVehicleOverrideMsg, + TimeOfDayMessage, // + UnknownMessage73, // PPT_PROJECTILE_EVENT_BLOCK + SpawnRequestMessage, // + DeployRequestMessage, // + UnknownMessage76, // PPT_BUILDINGSTATECHANGED + RepairMessage, // + ServerVehicleOverrideMsg, // LashMessage, // OPCODES 0x50-5f - TargetingInfoMessage, - TriggerEffectMessage, - WeaponDryFireMessage, - DroppodLaunchRequestMessage, - HackMessage, - DroppodLaunchResponseMessage, - GenericObjectActionMessage, - AvatarVehicleTimerMessage, + TargetingInfoMessage, // + TriggerEffectMessage, // + WeaponDryFireMessage, // + DroppodLaunchRequestMessage, // + HackMessage, // + DroppodLaunchResponseMessage, // + GenericObjectActionMessage, // + AvatarVehicleTimerMessage, // // 0x58 - AvatarImplantMessage, - UnknownMessage89, // PPT_SEARCHMESSAGE - DelayedPathMountMsg, - OrbitalShuttleTimeMsg, - AIDamage, - DeployObjectMessage, - FavoritesRequest, - FavoritesResponse, + AvatarImplantMessage, // + UnknownMessage89, // PPT_SEARCHMESSAGE + DelayedPathMountMsg, // + OrbitalShuttleTimeMsg, // + AIDamage, // + DeployObjectMessage, // + FavoritesRequest, // + FavoritesResponse, // // OPCODES 0x60-6f - FavoritesMessage, - ObjectDetectedMessage, - SplashHitMessage, - SetChatFilterMessage, - AvatarSearchCriteriaMessage, - AvatarSearchResponse, - WeaponJammedMessage, - LinkDeadAwarenessMsg, + FavoritesMessage, // + ObjectDetectedMessage, // + SplashHitMessage, // + SetChatFilterMessage, // + AvatarSearchCriteriaMessage, // + AvatarSearchResponse, // + WeaponJammedMessage, // + LinkDeadAwarenessMsg, // // 0x68 - DroppodFreefallingMessage, - AvatarFirstTimeEventMessage, - AggravatedDamageMessage, - TriggerSoundMessage, - LootItemMessage, - VehicleSubStateMessage, - SquadMembershipRequest, - SquadMembershipResponse, + DroppodFreefallingMessage, // + AvatarFirstTimeEventMessage, // + AggravatedDamageMessage, // + TriggerSoundMessage, // + LootItemMessage, // + VehicleSubStateMessage, // + SquadMembershipRequest, // + SquadMembershipResponse, // // OPCODES 0x70-7f - SquadMemberEvent, - PlatoonEvent, - FriendsRequest, - FriendsResponse, - TriggerEnvironmentalDamageMessage, - TrainingZoneMessage, - DeployableObjectsInfoMessage, + SquadMemberEvent, // + PlatoonEvent, // + FriendsRequest, // + FriendsResponse, // + TriggerEnvironmentalDamageMessage, // + TrainingZoneMessage, // + DeployableObjectsInfoMessage, // SquadState, // 0x78 - OxygenStateMessage, - TradeMessage, - UnknownMessage122, - DamageFeedbackMessage, - DismountBuildingMsg, - UnknownMessage125, // PPT_MOUNTBUILDING - UnknownMessage126, // PPT_INTENDEDDROPZONE - AvatarStatisticsMessage, + OxygenStateMessage, // + TradeMessage, // + UnknownMessage122, // + DamageFeedbackMessage, // + DismountBuildingMsg, // + UnknownMessage125, // PPT_MOUNTBUILDING + UnknownMessage126, // PPT_INTENDEDDROPZONE + AvatarStatisticsMessage, // // OPCODES 0x80-8f - GenericObjectAction2Message, - DestroyDisplayMessage, - TriggerBotAction, - SquadWaypointRequest, - SquadWaypointEvent, - OffshoreVehicleMessage, - ObjectDeployedMessage, - ObjectDeployedCountMessage, + GenericObjectAction2Message, // + DestroyDisplayMessage, // + TriggerBotAction, // + SquadWaypointRequest, // + SquadWaypointEvent, // + OffshoreVehicleMessage, // + ObjectDeployedMessage, // + ObjectDeployedCountMessage, // // 0x88 - WeaponDelayFireMessage, - BugReportMessage, - PlayerStasisMessage, - UnknownMessage139, - OutfitMembershipRequest, - OutfitMembershipResponse, - OutfitRequest, - OutfitEvent, + WeaponDelayFireMessage, // + BugReportMessage, // + PlayerStasisMessage, // + UnknownMessage139, // + OutfitMembershipRequest, // + OutfitMembershipResponse, // + OutfitRequest, // + OutfitEvent, // // OPCODES 0x90-9f - OutfitMemberEvent, - OutfitMemberUpdate, - PlanetsideStringAttributeMessage, - DataChallengeMessage, - DataChallengeMessageResp, - WeatherMessage, - SimDataChallenge, - SimDataChallengeResp, + OutfitMemberEvent, // + OutfitMemberUpdate, // + PlanetsideStringAttributeMessage, // + DataChallengeMessage, // + DataChallengeMessageResp, // + WeatherMessage, // + SimDataChallenge, // + SimDataChallengeResp, // // 0x98 - OutfitListEvent, - EmpireIncentivesMessage, - InvalidTerrainMessage, - SyncMessage, - DebugDrawMessage, - SoulMarkMessage, - UplinkPositionEvent, - HotSpotUpdateMessage, + OutfitListEvent, // + EmpireIncentivesMessage, // + InvalidTerrainMessage, // + SyncMessage, // + DebugDrawMessage, // + SoulMarkMessage, // + UplinkPositionEvent, // + HotSpotUpdateMessage, // // OPCODES 0xa0-af - BuildingInfoUpdateMessage, - FireHintMessage, - UplinkRequest, - UplinkResponse, - WarpgateRequest, - WarpgateResponse, - DamageWithPositionMessage, - GenericActionMessage, + BuildingInfoUpdateMessage, // + FireHintMessage, // + UplinkRequest, // + UplinkResponse, // + WarpgateRequest, // + WarpgateResponse, // + DamageWithPositionMessage, // + GenericActionMessage, // // 0xa8 - ContinentalLockUpdateMessage, - AvatarGrenadeStateMessage, - UnknownMessage170, - UnknownMessage171, - ReleaseAvatarRequestMessage, - AvatarDeadStateMessage, - CSAssistMessage, - CSAssistCommentMessage, + ContinentalLockUpdateMessage, // + AvatarGrenadeStateMessage, // + UnknownMessage170, // + UnknownMessage171, // + ReleaseAvatarRequestMessage, // + AvatarDeadStateMessage, // + CSAssistMessage, // + CSAssistCommentMessage, // // OPCODES 0xb0-bf - VoiceHostRequest, - VoiceHostKill, - VoiceHostInfo, - BattleplanMessage, - BattleExperienceMessage, - TargetingImplantRequest, - ZonePopulationUpdateMessage, - DisconnectMessage, + VoiceHostRequest, // + VoiceHostKill, // + VoiceHostInfo, // + BattleplanMessage, // + BattleExperienceMessage, // + TargetingImplantRequest, // + ZonePopulationUpdateMessage, // + DisconnectMessage, // // 0xb8 - ExperienceAddedMessage, - OrbitalStrikeWaypointMessage, - KeepAliveMessage, - MapObjectStateBlockMessage, - SnoopMsg, - PlayerStateMessageUpstream, - PlayerStateShiftMessage, - ZipLineMessage, + ExperienceAddedMessage, // + OrbitalStrikeWaypointMessage, // + KeepAliveMessage, // + MapObjectStateBlockMessage, // + SnoopMsg, // + PlayerStateMessageUpstream, // + PlayerStateShiftMessage, // + ZipLineMessage, // // OPCODES 0xc0-cf - CaptureFlagUpdateMessage, - VanuModuleUpdateMessage, - FacilityBenefitShieldChargeRequestMessage, - ProximityTerminalUseMessage, - QuantityDeltaUpdateMessage, - ChainLashMessage, - ZoneInfoMessage, - LongRangeProjectileInfoMessage, + CaptureFlagUpdateMessage, // + VanuModuleUpdateMessage, // + FacilityBenefitShieldChargeRequestMessage, // + ProximityTerminalUseMessage, // + QuantityDeltaUpdateMessage, // + ChainLashMessage, // + ZoneInfoMessage, // + LongRangeProjectileInfoMessage, // // 0xc8 - WeaponLazeTargetPositionMessage, - ModuleLimitsMessage, - OutfitBenefitMessage, - EmpireChangeTimeMessage, - ClockCalibrationMessage, - DensityLevelUpdateMessage, - ActOfGodMessage, - AvatarAwardMessage, + WeaponLazeTargetPositionMessage, // + ModuleLimitsMessage, // + OutfitBenefitMessage, // + EmpireChangeTimeMessage, // + ClockCalibrationMessage, // + DensityLevelUpdateMessage, // + ActOfGodMessage, // + AvatarAwardMessage, // // OPCODES 0xd0-df - UnknownMessage208, - DisplayedAwardMessage, - RespawnAMSInfoMessage, - ComponentDamageMessage, - GenericObjectActionAtPositionMessage, - PropertyOverrideMessage, - WarpgateLinkOverrideMessage, - EmpireBenefitsMessage, + UnknownMessage208, // + DisplayedAwardMessage, // + RespawnAMSInfoMessage, // + ComponentDamageMessage, // + GenericObjectActionAtPositionMessage, // + PropertyOverrideMessage, // + WarpgateLinkOverrideMessage, // + EmpireBenefitsMessage, // // 0xd8 - ForceEmpireMessage, - BroadcastWarpgateUpdateMessage, - UnknownMessage218, - SquadMainTerminalMessage, - SquadMainTerminalResponseMessage, - SquadOrderMessage, - SquadOrderResponse, - ZoneLockInfoMessage, + ForceEmpireMessage, // + BroadcastWarpgateUpdateMessage, // + UnknownMessage218, // + SquadMainTerminalMessage, // + SquadMainTerminalResponseMessage, // + SquadOrderMessage, // + SquadOrderResponse, // + ZoneLockInfoMessage, // // OPCODES 0xe0-ef - SquadBindInfoMessage, - AudioSequenceMessage, - SquadFacilityBindInfoMessage, - ZoneForcedCavernConnectionsMessage, - MissionActionMessage, - MissionKillTriggerMessage, - ReplicationStreamMessage, - SquadDefinitionActionMessage, + SquadBindInfoMessage, // + AudioSequenceMessage, // + SquadFacilityBindInfoMessage, // + ZoneForcedCavernConnectionsMessage, // + MissionActionMessage, // + MissionKillTriggerMessage, // + ReplicationStreamMessage, // + SquadDefinitionActionMessage, // // 0xe8 - SquadDetailDefinitionUpdateMessage, - TacticsMessage, - RabbitUpdateMessage, - SquadInvitationRequestMessage, - CharacterKnowledgeMessage, - GameScoreUpdateMessage, - UnknownMessage238, - OrderTerminalBugMessage, + SquadDetailDefinitionUpdateMessage, // + TacticsMessage, // + RabbitUpdateMessage, // + SquadInvitationRequestMessage, // + CharacterKnowledgeMessage, // + GameScoreUpdateMessage, // + UnknownMessage238, // + OrderTerminalBugMessage, // // OPCODES 0xf0-f3 - QueueTimedHelpMessage, - MailMessage, - GameVarUpdate, - ClientCheatedMessage // last known message type (243, 0xf3) + QueueTimedHelpMessage, // + MailMessage, // + GameVarUpdate, // + ClientCheatedMessage // last known message type (243, 0xf3) = Value private def noDecoder(opcode: GamePacketOpcode.Type) = - (_: BitVector) => Attempt.failure(Err(s"Could not find a marshaller for game packet $opcode")) + (bits: BitVector) => Attempt.failure(Err(s"Could not find a marshaller for game packet $opcode (${bits.toHex}")) /// Mapping of packet IDs to decoders. Notice that we are using the @switch annotation which ensures that the Scala /// compiler will be able to optimize this as a lookup table (switch statement). Microbenchmarks show a nearly 400x From 406d55bae7bca89572f7b1b333ca7a9fe25719d2 Mon Sep 17 00:00:00 2001 From: Jakob Gillich Date: Sat, 17 Apr 2021 10:06:59 +0200 Subject: [PATCH 06/13] add Unknown30 decoder, allow non-advanced packets --- .../actors/net/MiddlewareActor.scala | 151 ++++++++++-------- .../packet/ControlPacketOpcode.scala | 45 ++++-- .../scala/net/psforever/packet/PSPacket.scala | 5 +- .../net/psforever/packet/PacketCoding.scala | 19 ++- .../psforever/packet/control/Unknown30.scala | 18 +++ 5 files changed, 146 insertions(+), 92 deletions(-) create mode 100644 src/main/scala/net/psforever/packet/control/Unknown30.scala diff --git a/src/main/scala/net/psforever/actors/net/MiddlewareActor.scala b/src/main/scala/net/psforever/actors/net/MiddlewareActor.scala index a5093e1d..80c4e31f 100644 --- a/src/main/scala/net/psforever/actors/net/MiddlewareActor.scala +++ b/src/main/scala/net/psforever/actors/net/MiddlewareActor.scala @@ -129,7 +129,7 @@ object MiddlewareActor { * Do nothing. * Wait to be told to do something. */ - private def doNothing(): Unit = { } + private def doNothing(): Unit = {} } /** @@ -182,7 +182,8 @@ class MiddlewareActor( val outQueueBundled: mutable.Queue[PlanetSidePacket] = mutable.Queue() /** Latest outbound sequence number; - * the current sequence is one less than this number */ + * the current sequence is one less than this number + */ var outSequence = 0 /** @@ -202,7 +203,8 @@ class MiddlewareActor( } /** Latest outbound subslot number; - * the current subslot is one less than this number */ + * the current subslot is one less than this number + */ var outSubslot = 0 /** @@ -224,12 +226,13 @@ class MiddlewareActor( /** * Do not bundle these packets together with other packets */ - val packetsBundledByThemselves: List[PlanetSidePacket=>Boolean] = List( + val packetsBundledByThemselves: List[PlanetSidePacket => Boolean] = List( MiddlewareActor.keepAliveMessageGuard, MiddlewareActor.characterInfoMessageGuard ) val smpHistoryLength: Int = 100 + /** History of created `SlottedMetaPacket`s. * In case the client does not register receiving a packet by checking against packet subslot index numbers, * it will dispatch a `RelatedA` packet, @@ -239,24 +242,32 @@ class MiddlewareActor( * The client and server supposedly maintain reciprocating mechanisms. */ val preparedSlottedMetaPackets: Array[SlottedMetaPacket] = new Array[SlottedMetaPacket](smpHistoryLength) - var nextSmpIndex: Int = 0 - var acceptedSmpSubslot: Int = 0 + var nextSmpIndex: Int = 0 + var acceptedSmpSubslot: Int = 0 /** end of life stat */ var timesInReorderQueue: Int = 0 + /** end of life stat */ var timesSubslotMissing: Int = 0 + /** Delay between runs of the packet bundler/resolver timer (ms); - * 250ms per network update (client upstream), so 10 runs of this bundling code every update */ + * 250ms per network update (client upstream), so 10 runs of this bundling code every update + */ val packetProcessorDelay = Config.app.network.middleware.packetBundlingDelay + /** Timer that handles the bundling and throttling of outgoing packets and resolves disorganized inbound packets */ var packetProcessor: Cancellable = Default.Cancellable + /** how long packets that are out of sequential order wait for the missing sequence before being expedited (ms) */ val inReorderTimeout = Config.app.network.middleware.inReorderTimeout + /** Timer that handles the bundling and throttling of outgoing packets requesting packets with known subslot numbers */ var subslotMissingProcessor: Cancellable = Default.Cancellable + /** how long to wait between repeated requests for packets with known missing subslot numbers (ms) */ val inSubslotMissingDelay = Config.app.network.middleware.inSubslotMissingDelay + /** how many time to repeat the request for a packet with a known missing subslot number */ val inSubslotMissingNumberOfAttempts = Config.app.network.middleware.inSubslotMissingAttempts @@ -274,6 +285,13 @@ class MiddlewareActor( send(ServerStart(nonce, serverNonce), None, None) cryptoSetup() + /** Unknown30 is used to reuse an existing crypto session when switching from login to world + * When not handling it, it appears that the client will fall back to using ClientStart + * TODO implement this + */ + case (Unknown30(nonce), _) => + connectionClose() + // TODO ResetSequence case _ => log.warn(s"Unexpected packet type $packet in start (before crypto)") @@ -356,17 +374,17 @@ class MiddlewareActor( packet match { case (ClientFinished(clientPubKey, _), Some(_)) => serverMACBuffer ++= msg.drop(3) - val agreedKey = dh.agree(clientPubKey.toArray) + val agreedKey = dh.agree(clientPubKey.toArray) val agreedMessage = ByteVector("master secret".getBytes) ++ clientChallenge ++ hex"00000000" ++ serverChallenge ++ hex"00000000" - val masterSecret = new Md5Mac(ByteVector.view(agreedKey)).updateFinal(agreedMessage) - val mac = new Md5Mac(masterSecret) + val masterSecret = new Md5Mac(ByteVector.view(agreedKey)).updateFinal(agreedMessage) + val mac = new Md5Mac(masterSecret) //TODO verify client challenge? val serverChallengeResult = mac .updateFinal(ByteVector("server finished".getBytes) ++ serverMACBuffer ++ hex"01", 0xc) - val encExpansion = ByteVector.view("server expansion".getBytes) ++ hex"0000" ++ serverChallenge ++ + val encExpansion = ByteVector.view("server expansion".getBytes) ++ hex"0000" ++ serverChallenge ++ hex"00000000" ++ clientChallenge ++ hex"00000000" - val decExpansion = ByteVector.view("client expansion".getBytes) ++ hex"0000" ++ serverChallenge ++ + val decExpansion = ByteVector.view("client expansion".getBytes) ++ hex"0000" ++ serverChallenge ++ hex"00000000" ++ clientChallenge ++ hex"00000000" val expandedEncKey = mac.updateFinal(encExpansion, 64) val expandedDecKey = mac.updateFinal(decExpansion, 64) @@ -381,13 +399,12 @@ class MiddlewareActor( ) send(ServerFinished(serverChallengeResult)) //start the queue processor loop - packetProcessor = - context.system.scheduler.scheduleWithFixedDelay( - packetProcessorDelay, - packetProcessorDelay - )(()=> { - context.self ! ProcessQueue() - }) + packetProcessor = context.system.scheduler.scheduleWithFixedDelay( + packetProcessorDelay, + packetProcessorDelay + )(() => { + context.self ! ProcessQueue() + }) active() case other => @@ -416,7 +433,7 @@ class MiddlewareActor( activeSequenceFunc(packet, sequence) case Successful((packet, None)) => in(packet) - case Failure(e) => + case Failure(e) => log.error(s"Could not decode $connectionId's packet: $e") } Behaviors.same @@ -446,7 +463,7 @@ class MiddlewareActor( val onSignal: PartialFunction[(ActorContext[Command], Signal), Behavior[Command]] = { case (_, PostStop) => context.stop(nextActor) - if(timesInReorderQueue > 0 || timesSubslotMissing > 0) { + if (timesInReorderQueue > 0 || timesSubslotMissing > 0) { log.trace(s"out of sequence checks: $timesInReorderQueue, subslot missing checks: $timesSubslotMissing") } packetProcessor.cancel() @@ -575,31 +592,29 @@ class MiddlewareActor( } else if (outQueue.nonEmpty) { val bundle = { var length = 0L - val (_, bundle) = outQueue - .dequeueWhile { - case (packet, payload) => - // packet length + MultiPacketEx header length - val packetLength = payload.length + ( - if (payload.length < 2048) { 8L } //256 * 8; 1L * 8 - else if (payload.length < 524288) { 16L } //65536 * 8; 2L * 8 - else { 32L } //4L * 8 - ) - length += packetLength + val (_, bundle) = outQueue.dequeueWhile { + case (packet, payload) => + // packet length + MultiPacketEx header length + val packetLength = payload.length + ( + if (payload.length < 2048) { 8L } //256 * 8; 1L * 8 + else if (payload.length < 524288) { 16L } //65536 * 8; 2L * 8 + else { 32L } //4L * 8 + ) + length += packetLength - if (packetsBundledByThemselves.exists { _(packet) }) { - if (length == packetLength) { - length += MTU - true //dequeue only packet - } else { - false //dequeue later - } + if (packetsBundledByThemselves.exists { _(packet) }) { + if (length == packetLength) { + length += MTU + true //dequeue only packet } else { - // Some packets may be larger than the MTU limit, in that case we dequeue anyway and split later - // We deduct some bytes to leave room for SlottedMetaPacket (4 bytes) and MultiPacketEx (2 bytes + prefix per packet) - length == packetLength || length <= (MTU - 6) * 8 + false //dequeue later } - } - .unzip + } else { + // Some packets may be larger than the MTU limit, in that case we dequeue anyway and split later + // We deduct some bytes to leave room for SlottedMetaPacket (4 bytes) and MultiPacketEx (2 bytes + prefix per packet) + length == packetLength || length <= (MTU - 6) * 8 + } + }.unzip bundle } @@ -616,7 +631,7 @@ class MiddlewareActor( case Successful(data) => outQueueBundled.enqueue(smp(slot = 0, data.bytes)) sendFirstBundle() - case Failure(cause) => + case Failure(cause) => log.error(s"could not bundle $bundle: ${cause.message}") //to avoid packets being lost, unwrap bundle and queue the packets individually bundle.foreach { packet => @@ -636,7 +651,7 @@ class MiddlewareActor( * @see `activeNormal` * @see `activeWithReordering` */ - private var activeSequenceFunc: (PlanetSidePacket, Int)=>Unit = activeNormal + private var activeSequenceFunc: (PlanetSidePacket, Int) => Unit = activeNormal /** * Properly handle the newly-arrived packet based on its sequence number. @@ -651,7 +666,7 @@ class MiddlewareActor( if (sequence == inSequence + 1) { inSequence = sequence in(packet) - } else if(sequence < inSequence) { //expedite this packet + } else if (sequence < inSequence) { //expedite this packet in(packet) } else if (sequence == inSequence) { //do nothing? @@ -681,7 +696,7 @@ class MiddlewareActor( inSequence = sequence in(packet) processInReorderQueue() - } else if(sequence < inSequence) { //expedite this packet + } else if (sequence < inSequence) { //expedite this packet inReorderQueue.filterInPlace(_.sequence == sequence) in(packet) inReorderQueueFunc = inReorderQueueTest @@ -690,7 +705,7 @@ class MiddlewareActor( //do nothing? } else { var insertAtIndex = 0 - val length = inReorderQueue.length + val length = inReorderQueue.length while (insertAtIndex < length && sequence >= inReorderQueue(insertAtIndex).sequence) { insertAtIndex += 1 } @@ -704,7 +719,7 @@ class MiddlewareActor( * @see `inReorderQueueTest` * @see `processInReorderQueueTimeoutOnly` */ - private var inReorderQueueFunc: ()=>Unit = doNothing + private var inReorderQueueFunc: () => Unit = doNothing /** * Examine inbound packets that need to be reordered by sequence number and @@ -715,9 +730,9 @@ class MiddlewareActor( */ def processInReorderQueue(): Unit = { timesInReorderQueue += 1 - var currentSequence = inSequence - val currentTime = System.currentTimeMillis() - val takenPackets = (inReorderQueue.indexWhere { currentTime - _.time > inReorderTimeout.toMillis } match { + var currentSequence = inSequence + val currentTime = System.currentTimeMillis() + val takenPackets = (inReorderQueue.indexWhere { currentTime - _.time > inReorderTimeout.toMillis } match { case -1 => inReorderQueue .takeWhile { entry => @@ -731,7 +746,7 @@ class MiddlewareActor( } case index => // Forward all packets ahead of any packet that has been in the queue for 50ms - val entries = inReorderQueue.take(index + 1) + val entries = inReorderQueue.take(index + 1) currentSequence = entries.last.sequence entries }).map(_.packet) @@ -757,7 +772,7 @@ class MiddlewareActor( inReorderQueue.dropInPlace(takenPackets.length) takenPackets.foreach { p => inReorderQueueFunc = inReorderQueueTest - inSequence = p.sequence + inSequence = p.sequence in(p.packet) } } @@ -783,7 +798,7 @@ class MiddlewareActor( * @see `inSubslotNotMissing` * @see `inSubslotMissingRequests` */ - private var activeSubslotsFunc: (Int, Int, ByteVector)=>Unit = inSubslotNotMissing + private var activeSubslotsFunc: (Int, Int, ByteVector) => Unit = inSubslotNotMissing /** * What to do with a `SlottedMetaPacket` control packet normally. @@ -851,7 +866,7 @@ class MiddlewareActor( * resume normal operations when acting upon inbound `SlottedMetaPacket` packets. * @param slot the optional slot to report the "first" `RelatedB` in a "while" */ - def inSubslotsMissingRequestsFinished(slot: Int = 0) : Unit = { + def inSubslotsMissingRequestsFinished(slot: Int = 0): Unit = { if (inSubslotsMissing.isEmpty) { subslotMissingProcessor.cancel() activeSubslotsFunc = inSubslotNotMissing @@ -870,25 +885,25 @@ class MiddlewareActor( */ def askForMissingSubslots(): Unit = { if (subslotMissingProcessor.isCancelled) { - subslotMissingProcessor = - context.system.scheduler.scheduleWithFixedDelay( - initialDelay = 0.milliseconds, - inSubslotMissingDelay - )(()=> { - inSubslotsMissing.synchronized { - timesSubslotMissing += inSubslotsMissing.size - inSubslotsMissing.foreach { case (subslot, attempt) => + subslotMissingProcessor = context.system.scheduler.scheduleWithFixedDelay( + initialDelay = 0.milliseconds, + inSubslotMissingDelay + )(() => { + inSubslotsMissing.synchronized { + timesSubslotMissing += inSubslotsMissing.size + inSubslotsMissing.foreach { + case (subslot, attempt) => val value = attempt - 1 - if(value > 0) { + if (value > 0) { inSubslotsMissing(subslot) = value } else { inSubslotsMissing.remove(subslot) } send(RelatedA(0, subslot)) - } - inSubslotsMissingRequestsFinished() } - }) + inSubslotsMissingRequestsFinished() + } + }) } } diff --git a/src/main/scala/net/psforever/packet/ControlPacketOpcode.scala b/src/main/scala/net/psforever/packet/ControlPacketOpcode.scala index c53e1624..0fe9d1c5 100644 --- a/src/main/scala/net/psforever/packet/ControlPacketOpcode.scala +++ b/src/main/scala/net/psforever/packet/ControlPacketOpcode.scala @@ -12,20 +12,41 @@ object ControlPacketOpcode extends Enumeration { type Type = Value val // OPCODES 0x00-0f - HandleGamePacket, // a whoopsi case: not actually a control packet, but a game packet - ClientStart, // first packet ever sent during client connection - ServerStart, // second packet sent in response to ClientStart - MultiPacket, // used to send multiple packets with one UDP message (subpackets limited to <= 255) - Unknown4, TeardownConnection, Unknown6, ControlSync, // sent to the server from the client + HandleGamePacket, // a whoopsi case: not actually a control packet, but a game packet + ClientStart, // first packet ever sent during client connection + ServerStart, // second packet sent in response to ClientStart + MultiPacket, // used to send multiple packets with one UDP message (subpackets limited to <= 255) + Unknown4, // + TeardownConnection, // + Unknown6, // + ControlSync, // sent to the server from the client // 0x08 - ControlSyncResp, // the response generated by the server - SlottedMetaPacket0, SlottedMetaPacket1, SlottedMetaPacket2, SlottedMetaPacket3, SlottedMetaPacket4, - SlottedMetaPacket5, SlottedMetaPacket6, + ControlSyncResp, // the response generated by the server + SlottedMetaPacket0, // + SlottedMetaPacket1, // + SlottedMetaPacket2, // + SlottedMetaPacket3, // + SlottedMetaPacket4, // + SlottedMetaPacket5, // + SlottedMetaPacket6, // // OPCODES 0x10-1f - SlottedMetaPacket7, RelatedA0, RelatedA1, RelatedA2, RelatedA3, RelatedB0, RelatedB1, RelatedB2, + SlottedMetaPacket7, // + RelatedA0, // + RelatedA1, // + RelatedA2, // + RelatedA3, // + RelatedB0, // + RelatedB1, // + RelatedB2, // // 0x18 - RelatedB3, MultiPacketEx, // same as MultiPacket, but with the ability to send extended length packets - Unknown26, Unknown27, Unknown28, ConnectionClose, Unknown30 = Value + RelatedB3, // + MultiPacketEx, // same as MultiPacket, but with the ability to send extended length packets + Unknown26, // + Unknown27, // + Unknown28, // + ConnectionClose, // + Unknown30 // Probably a more lightweight variant of ClientStart, containing only the client nonce + = Value private def noDecoder(opcode: ControlPacketOpcode.Type) = (bits: BitVector) => Attempt.failure(Err(s"Could not find a marshaller for control packet $opcode (${bits.toHex})")) @@ -69,7 +90,7 @@ object ControlPacketOpcode extends Enumeration { case 0x1b => noDecoder(Unknown27) case 0x1c => noDecoder(Unknown28) case 0x1d => control.ConnectionClose.decode - case 0x1e => noDecoder(Unknown30) + case 0x1e => control.Unknown30.decode case _ => noDecoder(opcode) } diff --git a/src/main/scala/net/psforever/packet/PSPacket.scala b/src/main/scala/net/psforever/packet/PSPacket.scala index e5262d55..b03be3dd 100644 --- a/src/main/scala/net/psforever/packet/PSPacket.scala +++ b/src/main/scala/net/psforever/packet/PSPacket.scala @@ -63,7 +63,7 @@ object PacketType extends Enumeration(1) { } /** PlanetSide packet flags (beginning of most packets) */ -final case class PlanetSidePacketFlags(packetType: PacketType.Value, secured: Boolean) +final case class PlanetSidePacketFlags(packetType: PacketType.Value, secured: Boolean, advanced: Boolean = true) /** Codec for [[PlanetSidePacketFlags]] */ object PlanetSidePacketFlags extends Marshallable[PlanetSidePacketFlags] { @@ -71,7 +71,8 @@ object PlanetSidePacketFlags extends Marshallable[PlanetSidePacketFlags] { ("packet_type" | PacketType.codec) :: // first 4-bits ("unused" | constant(bin"0")) :: ("secured" | bool) :: - ("advanced" | constant(bin"1")) :: // we only support "advanced packets" + //("advanced" | constant(bin"1")) :: // we only support "advanced packets" + ("advanced" | bool) :: ("length_specified" | constant(bin"0")) // we DO NOT support this field ).as[PlanetSidePacketFlags] } diff --git a/src/main/scala/net/psforever/packet/PacketCoding.scala b/src/main/scala/net/psforever/packet/PacketCoding.scala index 4c494610..214e5e24 100644 --- a/src/main/scala/net/psforever/packet/PacketCoding.scala +++ b/src/main/scala/net/psforever/packet/PacketCoding.scala @@ -42,7 +42,7 @@ object PacketCoding { case Some(_sequence) => uint16L.encode(_sequence) match { case Successful(_seq) => _seq - case f @ Failure(_) => return f + case f @ Failure(_) => return f } case None => return Failure(Err(s"Missing sequence")) @@ -125,7 +125,7 @@ object PacketCoding { case Successful(opcode) => Successful(opcode) case f @ Failure(_) => f } - + case _ => Failure(Err("packet not supported")) } @@ -174,7 +174,7 @@ object PacketCoding { ): Attempt[(PlanetSidePacket, Int)] = { val (flags, remainder) = Codec.decode[PlanetSidePacketFlags](BitVector(msg)) match { case Successful(DecodeResult(value, _remainder)) => (value, _remainder) - case Failure(e) => return Failure(Err(s"Failed to parse packet flags: ${e.message}")) + case Failure(e) => return Failure(Err(s"Failed to parse packet flags: ${e.message}")) } flags.packetType match { @@ -218,8 +218,8 @@ object PacketCoding { case (PacketType.ResetSequence, Some(_crypto)) => _crypto.decrypt(payload.drop(1)) match { case Successful(p) if p == hex"01" => Successful((ResetSequence(), sequence)) - case Successful(p) => Failure(Err(s"ResetSequence decrypted to unsupported value - $p")) - case _ => Failure(Err(s"ResetSequence did not decrypt properly")) + case Successful(p) => Failure(Err(s"ResetSequence decrypted to unsupported value - $p")) + case _ => Failure(Err(s"ResetSequence did not decrypt properly")) } case (ptype, _) => Failure(Err(s"Cannot unmarshal $ptype packet at all")) @@ -238,8 +238,7 @@ object PacketCoding { def decodePacket(msg: ByteVector): Attempt[PlanetSidePacket] = { if (msg.length < PLANETSIDE_MIN_PACKET_SIZE) return Failure(Err(s"Packet does not meet the minimum length of $PLANETSIDE_MIN_PACKET_SIZE bytes")) - val firstByte = msg { 0 } - firstByte match { + msg(0) match { case 0x00 => // control packets don't need the first byte ControlPacketOpcode.codec.decode(msg.drop(1).bits) match { @@ -303,7 +302,7 @@ object PacketCoding { } } catch { case e: Throwable => - val msg = if(e.getMessage == null) e.getClass.getSimpleName else e.getMessage + val msg = if (e.getMessage == null) e.getClass.getSimpleName else e.getMessage Failure(Err(s"encrypt error: '$msg' data: ${packetWithPadding.toHex}")) } } @@ -321,14 +320,14 @@ object PacketCoding { // last byte is the padding length val padding = uint8L.decode(payloadDecrypted.takeRight(1).bits) match { case Successful(_padding) => _padding.value - case Failure(e) => return Failure(Err(s"Failed to decode the encrypted padding length: ${e.message}")) + case Failure(e) => return Failure(Err(s"Failed to decode the encrypted padding length: ${e.message}")) } val payloadNoPadding = payloadDecrypted.dropRight(1 + padding) val payloadMac = payloadNoPadding.takeRight(Md5Mac.MACLENGTH) val mac = bytes(Md5Mac.MACLENGTH).decode(payloadMac.bits) match { - case Failure(e) => return Failure(Err("Failed to extract the encrypted MAC: " + e.message)) + case Failure(e) => return Failure(Err("Failed to extract the encrypted MAC: " + e.message)) case Successful(_mac) => _mac.value } diff --git a/src/main/scala/net/psforever/packet/control/Unknown30.scala b/src/main/scala/net/psforever/packet/control/Unknown30.scala new file mode 100644 index 00000000..a7ed734b --- /dev/null +++ b/src/main/scala/net/psforever/packet/control/Unknown30.scala @@ -0,0 +1,18 @@ +package net.psforever.packet.control + +import net.psforever.packet.{ControlPacketOpcode, Marshallable, PlanetSideControlPacket} +import scodec.Codec +import scodec.bits._ +import scodec.codecs._ + +final case class Unknown30(clientNonce: Long) extends PlanetSideControlPacket { + type Packet = Unknown30 + def opcode = ControlPacketOpcode.Unknown30 + def encode = Unknown30.encode(this) +} + +object Unknown30 extends Marshallable[Unknown30] { + implicit val codec: Codec[Unknown30] = ( + ("client_nonce" | uint32L) + ).as[Unknown30] +} From 9d3e468693e5dca10cf4837dba62e0cb8a71db2d Mon Sep 17 00:00:00 2001 From: Jakob Gillich Date: Sat, 17 Apr 2021 22:32:04 +0200 Subject: [PATCH 07/13] Fix CharacterInfoMessage being bundled with OCDMs --- .../scala/net/psforever/actors/net/MiddlewareActor.scala | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/scala/net/psforever/actors/net/MiddlewareActor.scala b/src/main/scala/net/psforever/actors/net/MiddlewareActor.scala index 80c4e31f..b8741be1 100644 --- a/src/main/scala/net/psforever/actors/net/MiddlewareActor.scala +++ b/src/main/scala/net/psforever/actors/net/MiddlewareActor.scala @@ -604,10 +604,10 @@ class MiddlewareActor( if (packetsBundledByThemselves.exists { _(packet) }) { if (length == packetLength) { - length += MTU - true //dequeue only packet + length = Long.MaxValue + true // dequeue only packet } else { - false //dequeue later + false // dequeue later } } else { // Some packets may be larger than the MTU limit, in that case we dequeue anyway and split later From 22de086bb8b0723c095c1d79f9d35168236ac317 Mon Sep 17 00:00:00 2001 From: Jakob Gillich Date: Sat, 17 Apr 2021 22:42:25 +0200 Subject: [PATCH 08/13] Middleware: Add MTU rather than setting length to max Don't want overflow errors here since the next iteration will still add their packet length. --- src/main/scala/net/psforever/actors/net/MiddlewareActor.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/net/psforever/actors/net/MiddlewareActor.scala b/src/main/scala/net/psforever/actors/net/MiddlewareActor.scala index b8741be1..c97ff2bf 100644 --- a/src/main/scala/net/psforever/actors/net/MiddlewareActor.scala +++ b/src/main/scala/net/psforever/actors/net/MiddlewareActor.scala @@ -604,7 +604,7 @@ class MiddlewareActor( if (packetsBundledByThemselves.exists { _(packet) }) { if (length == packetLength) { - length = Long.MaxValue + length += MTU * 8 true // dequeue only packet } else { false // dequeue later From 765262f51addd9dadee46c6dfd98752fe03fb1d8 Mon Sep 17 00:00:00 2001 From: Jakob Gillich Date: Sun, 18 Apr 2021 01:21:07 +0200 Subject: [PATCH 09/13] Send tactical squad chat only to squad members --- .../psforever/actors/session/ChatActor.scala | 93 +++++++++++-------- .../psforever/services/chat/ChatService.scala | 5 +- 2 files changed, 57 insertions(+), 41 deletions(-) diff --git a/src/main/scala/net/psforever/actors/session/ChatActor.scala b/src/main/scala/net/psforever/actors/session/ChatActor.scala index 3d8ede65..0b794725 100644 --- a/src/main/scala/net/psforever/actors/session/ChatActor.scala +++ b/src/main/scala/net/psforever/actors/session/ChatActor.scala @@ -363,7 +363,7 @@ class ChatActor( session.zone.Buildings.values }) .flatMap { building => building.Amenities.filter { _.isInstanceOf[ResourceSilo] } } - if(silos.isEmpty) { + if (silos.isEmpty) { sessionActor ! SessionActor.SendResponse( ChatMsg(UNK_229, true, "Server", s"no targets for ntu found with parameters $facility", None) ) @@ -371,24 +371,29 @@ class ChatActor( customNtuValue match { // x = n0% of maximum capacitance case Some(value) if value > -1 && value < 11 => - silos.collect { case silo: ResourceSilo => - silo.Actor ! ResourceSilo.UpdateChargeLevel(value * silo.MaxNtuCapacitor * 0.1f - silo.NtuCapacitor) + silos.collect { + case silo: ResourceSilo => + silo.Actor ! ResourceSilo.UpdateChargeLevel( + value * silo.MaxNtuCapacitor * 0.1f - silo.NtuCapacitor + ) } // capacitance set to x (where x > 10) exactly, within limits case Some(value) => - silos.collect { case silo: ResourceSilo => - silo.Actor ! ResourceSilo.UpdateChargeLevel(value - silo.NtuCapacitor) + silos.collect { + case silo: ResourceSilo => + silo.Actor ! ResourceSilo.UpdateChargeLevel(value - silo.NtuCapacitor) } case None => // x >= n0% of maximum capacitance and x <= maximum capacitance val rand = new scala.util.Random - silos.collect { case silo: ResourceSilo => - val a = 7 - val b = 10 - a - val tenth = silo.MaxNtuCapacitor * 0.1f - silo.Actor ! ResourceSilo.UpdateChargeLevel( - a * tenth + rand.nextFloat() * b * tenth - silo.NtuCapacitor - ) + silos.collect { + case silo: ResourceSilo => + val a = 7 + val b = 10 - a + val tenth = silo.MaxNtuCapacitor * 0.1f + silo.Actor ! ResourceSilo.UpdateChargeLevel( + a * tenth + rand.nextFloat() * b * tenth - silo.NtuCapacitor + ) } } @@ -402,17 +407,17 @@ class ChatActor( val (faction, factionPos): (PlanetSideEmpire.Value, Option[Int]) = args.zipWithIndex .map { case (factionName, pos) => (factionName.toLowerCase, pos) } .flatMap { - case ("tr", pos) => Some(PlanetSideEmpire.TR, pos) - case ("nc", pos) => Some(PlanetSideEmpire.NC, pos) - case ("vs", pos) => Some(PlanetSideEmpire.VS, pos) - case ("none", pos) => Some(PlanetSideEmpire.NEUTRAL, pos) - case ("bo", pos) => Some(PlanetSideEmpire.NEUTRAL, pos) + case ("tr", pos) => Some(PlanetSideEmpire.TR, pos) + case ("nc", pos) => Some(PlanetSideEmpire.NC, pos) + case ("vs", pos) => Some(PlanetSideEmpire.VS, pos) + case ("none", pos) => Some(PlanetSideEmpire.NEUTRAL, pos) + case ("bo", pos) => Some(PlanetSideEmpire.NEUTRAL, pos) case ("neutral", pos) => Some(PlanetSideEmpire.NEUTRAL, pos) - case _ => None + case _ => None } .headOption match { case Some((isFaction, pos)) => (isFaction, Some(pos)) - case None => (session.player.Faction, None) + case None => (session.player.Faction, None) } val (buildingsOption, buildingPos): (Option[Seq[Building]], Option[Int]) = args.zipWithIndex.flatMap { @@ -475,14 +480,11 @@ class ChatActor( // [all [|none]] (Some(1) | None, Some(0), None, Some(_), None) => val buildings: Seq[Building] = buildingsOption.getOrElse( - session.zone.Buildings - .values - .filter { building => - building.PlayersInSOI.exists { soiPlayer => - session.player.CharId == soiPlayer.CharId - } + session.zone.Buildings.values.filter { building => + building.PlayersInSOI.exists { soiPlayer => + session.player.CharId == soiPlayer.CharId } - .toSeq + }.toSeq ) buildings foreach { building => // TODO implement timer @@ -563,12 +565,21 @@ class ChatActor( ChatChannel.Default() ) - case (CMT_VOICE, _, _) => - chatService ! ChatService.Message( - session, - message.copy(recipient = session.player.Name), - ChatChannel.Default() - ) + case (CMT_VOICE, _, contents) => + // SH prefix are tactical voice macros only sent to squad + if (contents.startsWith("SH")) { + channels.foreach { + case channel: ChatChannel.Squad => + chatService ! ChatService.Message(session, message.copy(recipient = session.player.Name), channel) + case _ => + } + } else { + chatService ! ChatService.Message( + session, + message.copy(recipient = session.player.Name), + ChatChannel.Default() + ) + } case (CMT_TELL, _, _) if !session.player.silenced => chatService ! ChatService.Message( @@ -675,11 +686,11 @@ class ChatActor( case (CMT_WARP, _, contents) if gmCommandAllowed => val buffer = contents.toLowerCase.split("\\s+") val (coordinates, waypoint) = (buffer.lift(0), buffer.lift(1), buffer.lift(2)) match { - case (Some(x), Some(y), Some(z)) => (Some(x, y, z), None) - case (Some("to"), Some(character), None) => (None, None) // TODO not implemented - case (Some("near"), Some(objectName), None) => (None, None) // TODO not implemented - case (Some(waypoint), None, None) if waypoint.nonEmpty => (None, Some(waypoint)) - case _ => (None, None) + case (Some(x), Some(y), Some(z)) => (Some(x, y, z), None) + case (Some("to"), Some(character), None) => (None, None) // TODO not implemented + case (Some("near"), Some(objectName), None) => (None, None) // TODO not implemented + case (Some(waypoint), None, None) if waypoint.nonEmpty => (None, Some(waypoint)) + case _ => (None, None) } (coordinates, waypoint) match { case (Some((x, y, z)), None) if List(x, y, z).forall { str => @@ -690,7 +701,10 @@ class ChatActor( case (None, Some(waypoint)) if waypoint == "-list" => val zone = PointOfInterest.get(session.player.Zone.id) zone match { - case Some(zone: PointOfInterest) => sessionActor ! SessionActor.SendResponse(ChatMsg(UNK_229, true, "", PointOfInterest.listAll(zone), None)) + case Some(zone: PointOfInterest) => + sessionActor ! SessionActor.SendResponse( + ChatMsg(UNK_229, true, "", PointOfInterest.listAll(zone), None) + ) case _ => ChatMsg(UNK_229, true, "", s"unknown player zone '${session.player.Zone.id}'", None) } case (None, Some(waypoint)) if waypoint != "-help" => @@ -939,7 +953,8 @@ class ChatActor( case CMT_VOICE => if ( session.zone == fromSession.zone && - Vector3.Distance(session.player.Position, fromSession.player.Position) < 25 + Vector3.Distance(session.player.Position, fromSession.player.Position) < 25 || + message.contents.startsWith("SH") // tactical squad voice macro ) { sessionActor ! SessionActor.SendResponse(message) } diff --git a/src/main/scala/net/psforever/services/chat/ChatService.scala b/src/main/scala/net/psforever/services/chat/ChatService.scala index 0ea7ee04..e498f780 100644 --- a/src/main/scala/net/psforever/services/chat/ChatService.scala +++ b/src/main/scala/net/psforever/services/chat/ChatService.scala @@ -63,8 +63,9 @@ class ChatService(context: ActorContext[ChatService.Command]) extends AbstractBe case Message(session, message, channel) => (channel, message.messageType) match { - case (ChatChannel.Squad(_), CMT_SQUAD) => ; - case (ChatChannel.Default(), messageType) if messageType != CMT_SQUAD => ; + case (ChatChannel.Squad(_), CMT_SQUAD) => () + case (ChatChannel.Squad(_), CMT_VOICE) if message.contents.startsWith("SH") => () + case (ChatChannel.Default(), messageType) if messageType != CMT_SQUAD => () case _ => log.error(s"invalid chat channel $channel for messageType ${message.messageType}") return this From ce32a1a1ff6b2134185af7fadbb668583db122ae Mon Sep 17 00:00:00 2001 From: Jakob Gillich Date: Sun, 18 Apr 2021 01:33:06 +0200 Subject: [PATCH 10/13] Fix terminal hack clearing Fixes #759 --- .../actors/session/SessionActor.scala | 454 ++++++++++-------- .../services/local/LocalService.scala | 36 +- 2 files changed, 289 insertions(+), 201 deletions(-) diff --git a/src/main/scala/net/psforever/actors/session/SessionActor.scala b/src/main/scala/net/psforever/actors/session/SessionActor.scala index 786a48cb..7897b278 100644 --- a/src/main/scala/net/psforever/actors/session/SessionActor.scala +++ b/src/main/scala/net/psforever/actors/session/SessionActor.scala @@ -60,7 +60,12 @@ import net.psforever.services.local.support.{CaptureFlagManager, HackCaptureActo import net.psforever.services.local.{LocalAction, LocalResponse, LocalServiceMessage, LocalServiceResponse} import net.psforever.services.properties.PropertyOverrideManager import net.psforever.services.support.SupportActor -import net.psforever.services.teamwork.{SquadResponse, SquadServiceMessage, SquadServiceResponse, SquadAction => SquadServiceAction} +import net.psforever.services.teamwork.{ + SquadResponse, + SquadServiceMessage, + SquadServiceResponse, + SquadAction => SquadServiceAction +} import net.psforever.services.hart.HartTimer import net.psforever.services.vehicle.{VehicleAction, VehicleResponse, VehicleServiceMessage, VehicleServiceResponse} import net.psforever.services.{RemoverActor, Service, ServiceManager, InterstellarClusterService => ICS} @@ -202,7 +207,8 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con var setupAvatarFunc: () => Unit = AvatarCreate var setCurrentAvatarFunc: Player => Unit = SetCurrentAvatarNormally var persist: () => Unit = NoPersistence - var specialItemSlotGuid : Option[PlanetSideGUID] = None // If a special item (e.g. LLU) has been attached to the player the GUID should be stored here, or cleared when dropped, since the drop hotkey doesn't send the GUID of the object to be dropped. + var specialItemSlotGuid: Option[PlanetSideGUID] = + None // If a special item (e.g. LLU) has been attached to the player the GUID should be stored here, or cleared when dropped, since the drop hotkey doesn't send the GUID of the object to be dropped. /** * used during zone transfers to maintain reference to seated vehicle (which does not yet exist in the new zone) @@ -349,14 +355,20 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con out case None => //delete stale entity reference from client - log.warn(s"ValidObject - ${player.Name} has an invalid GUID ${id.get.guid}, believing it in ${player.Sex.possessive} locker") + log.warn( + s"ValidObject - ${player.Name} has an invalid GUID ${id.get.guid}, believing it in ${player.Sex.possessive} locker" + ) sendResponse(ObjectDeleteMessage(id.get, 0)) None } case Some(obj) if obj.HasGUID && obj.GUID != id.get => - log.error(s"ValidObject: ${player.Name} found an object that isn't the one ${player.Sex.pronounSubject} thought it was in zone ${continent.id}") - log.debug(s"ValidObject: potentially fatal error in ${continent.id} - requested ${id.get}, got ${obj.Definition.Name} with ${obj.GUID}; GUID mismatch") + log.error( + s"ValidObject: ${player.Name} found an object that isn't the one ${player.Sex.pronounSubject} thought it was in zone ${continent.id}" + ) + log.debug( + s"ValidObject: potentially fatal error in ${continent.id} - requested ${id.get}, got ${obj.Definition.Name} with ${obj.GUID}; GUID mismatch" + ) None case out @ Some(obj) if obj.HasGUID => @@ -570,23 +582,26 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con case Some(entry) if vehicle.Seats(entry.mount).occupant.contains(player) => Some(vehicle) case Some(entry) => - log.warn(s"TransferPassenger: $playerName tried to mount seat ${entry.mount} during summoning, but it was already occupied, and ${player.Sex.pronounSubject} was rebuked") + log.warn( + s"TransferPassenger: $playerName tried to mount seat ${entry.mount} during summoning, but it was already occupied, and ${player.Sex.pronounSubject} was rebuked" + ) None case None => //log.warn(s"TransferPassenger: $playerName is missing from the manifest of a summoning ${vehicle.Definition.Name} from ${vehicle.Zone.id}") None }).orElse { manifest.cargo.find { _.name.equals(playerName) } match { - case Some(entry) => - vehicle.CargoHolds(entry.mount).occupant match { - case out @ Some(cargo) if cargo.Seats(0).occupants.exists(_.Name.equals(playerName)) => - out - case _ => - None - } - case None => - None - }} match { + case Some(entry) => + vehicle.CargoHolds(entry.mount).occupant match { + case out @ Some(cargo) if cargo.Seats(0).occupants.exists(_.Name.equals(playerName)) => + out + case _ => + None + } + case None => + None + } + } match { case Some(v: Vehicle) => galaxyService ! Service.Leave(Some(temp_channel)) //temporary vehicle-specific channel (see above) deadState = DeadState.Release @@ -972,7 +987,9 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con case ztype => if (ztype != Zoning.Method.None) { - log.warn(s"SpawnPointResponse: ${player.Name}'s zoning was not in order at the time a response was received; attempting to guess what ${player.Sex.pronounSubject} wants to do") + log.warn( + s"SpawnPointResponse: ${player.Name}'s zoning was not in order at the time a response was received; attempting to guess what ${player.Sex.pronounSubject} wants to do" + ) } val previousZoningType = zoningType CancelZoningProcess() @@ -994,7 +1011,9 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con else LoadZonePhysicalSpawnPoint(zone.id, pos, ori, CountSpawnDelay(zone.id, spawnPoint, continent.id)) case None => - log.warn(s"SpawnPointResponse: ${player.Name} received no spawn point response when asking InterstellarClusterService; sending home") + log.warn( + s"SpawnPointResponse: ${player.Name} received no spawn point response when asking InterstellarClusterService; sending home" + ) //Thread.sleep(1000) // throttle in case of infinite loop RequestSanctuaryZoneSpawn(player, currentZone = 0) } @@ -1137,7 +1156,9 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con log.warn( s"FinalizeDeployable: deployable ${definition.Item}@$guid not handled by specific case" ) - log.warn(s"FinalizeDeployable: deployable ${definition.Item}@$guid will be cleaned up, but may not get unregistered properly") + log.warn( + s"FinalizeDeployable: deployable ${definition.Item}@$guid will be cleaned up, but may not get unregistered properly" + ) TryDropFDU(tool, index, obj.Position) obj.Position = Vector3.Zero continent.Deployables ! Zone.Deployable.Dismiss(obj) @@ -1382,8 +1403,9 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con } else { keepAliveFunc = GetMountableAndSeat(None, player, continent) match { case (Some(v: Vehicle), Some(seatNumber)) - if seatNumber > 0 && v.WeaponControlledFromSeat(seatNumber).isEmpty => KeepAlivePersistence - case _ => NormalKeepAlive + if seatNumber > 0 && v.WeaponControlledFromSeat(seatNumber).isEmpty => + KeepAlivePersistence + case _ => NormalKeepAlive } } //if not the condition above, player has started playing normally @@ -1784,7 +1806,7 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con case AvatarResponse.EnvironmentalDamage(target, source, amount) => CancelZoningProcessWithDescriptiveReason("cancel_dmg") - //TODO damage marker? + //TODO damage marker? case AvatarResponse.Destroy(victim, killer, weapon, pos) => // guid = victim // killer = killer ;) @@ -1897,7 +1919,7 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con DrowningTarget(player.guid, player.progress, player.state), vehicle match { case Some(vinfo) => Some(DrowningTarget(vinfo.guid, vinfo.progress, vinfo.state)) - case None => None + case None => None } ) ) @@ -2331,7 +2353,7 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con } case LocalResponse.SendHackMessageHackCleared(target_guid, unk1, unk2) => - //log.trace(s"Clearing hack for $target_guid") + sendResponse(HackMessage(0, target_guid, guid, 0, unk1, HackState.HackCleared, unk2)) case LocalResponse.HackObject(target_guid, unk1, unk2) => HackObject(target_guid, unk1, unk2) @@ -2353,11 +2375,13 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con case LocalResponse.LluSpawned(llu) => // Create LLU on client - sendResponse(ObjectCreateMessage( - llu.Definition.ObjectId, - llu.GUID, - llu.Definition.Packet.ConstructorData(llu).get - )) + sendResponse( + ObjectCreateMessage( + llu.Definition.ObjectId, + llu.GUID, + llu.Definition.Packet.ConstructorData(llu).get + ) + ) sendResponse(TriggerSoundMessage(TriggeredSound.LLUMaterialize, llu.Position, unk = 20, 0.8000001f)) @@ -2399,8 +2423,11 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con case LocalResponse.ShuttleEvent(ev) => val msg = OrbitalShuttleTimeMsg( - ev.u1, ev.u2, - ev.t1, ev.t2, ev.t3, + ev.u1, + ev.u2, + ev.t1, + ev.t2, + ev.t3, ev.pairs.map { case ((a, b), c) => PadAndShuttlePair(a, b, c) } ) sendResponse(msg) @@ -2468,8 +2495,7 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con MountingAction(tplayer, obj, seat_number) keepAliveFunc = KeepAlivePersistence - case Mountable.CanMount(obj: Vehicle, seat_number, _) - if obj.Definition == GlobalDefinitions.orbital_shuttle => + case Mountable.CanMount(obj: Vehicle, seat_number, _) if obj.Definition == GlobalDefinitions.orbital_shuttle => CancelZoningProcessWithDescriptiveReason("cancel_mount") log.info(s"${player.Name} mounts the orbital shuttle") CancelAllProximityUnits() @@ -2478,13 +2504,11 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con case Mountable.CanMount(obj: Vehicle, seat_number, _) => CancelZoningProcessWithDescriptiveReason("cancel_mount") - log.info(s"${player.Name} mounts ${obj.Definition.Name} in ${ - obj.SeatPermissionGroup(seat_number) match { - case Some(AccessPermissionGroup.Driver) => "the driver seat" - case Some(seatType) => s"a $seatType seat, #$seat_number" - case None => "a seat" - } - }") + log.info(s"${player.Name} mounts ${obj.Definition.Name} in ${obj.SeatPermissionGroup(seat_number) match { + case Some(AccessPermissionGroup.Driver) => "the driver seat" + case Some(seatType) => s"a $seatType seat, #$seat_number" + case None => "a seat" + }}") val obj_guid: PlanetSideGUID = obj.GUID CancelAllProximityUnits() sendResponse(PlanetsideAttributeMessage(obj_guid, 0, obj.Health)) @@ -2541,12 +2565,12 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con DismountAction(tplayer, obj, seat_num) case Mountable.CanDismount(obj: Vehicle, seat_num, mount_point) - if obj.Definition == GlobalDefinitions.orbital_shuttle => + if obj.Definition == GlobalDefinitions.orbital_shuttle => val pguid = player.GUID if (obj.MountedIn.nonEmpty) { //dismount to hart lobby log.info(s"${tplayer.Name} dismounts the orbital shuttle into the lobby") - val sguid = obj.GUID + val sguid = obj.GUID val (pos, zang) = Vehicles.dismountShuttle(obj, mount_point) tplayer.Position = pos sendResponse(DelayedPathMountMsg(pguid, sguid, 60, true)) @@ -2554,8 +2578,7 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con continent.id, LocalAction.SendResponse(ObjectDetachMessage(sguid, pguid, pos, 0, 0, zang)) ) - } - else { + } else { //get ready for orbital drop DismountAction(tplayer, obj, seat_num) log.info(s"${player.Name} is prepped for dropping") @@ -2582,8 +2605,7 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con } keepAliveFunc = NormalKeepAlive - case Mountable.CanDismount(obj: Vehicle, seat_num, _) - if obj.Definition == GlobalDefinitions.droppod => + case Mountable.CanDismount(obj: Vehicle, seat_num, _) if obj.Definition == GlobalDefinitions.droppod => log.info(s"${tplayer.Name} has landed on ${continent.id}") UnaccessContainer(obj) DismountAction(tplayer, obj, seat_num) @@ -2952,7 +2974,7 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con sendResponse(PlanetsideAttributeMessage(player.GUID, 21, vehicle_guid)) //ownership vehicle.MountPoints.find { case (_, mp) => mp.seatIndex == 0 } match { case Some((mountPoint, _)) => vehicle.Actor ! Mountable.TryMount(player, mountPoint) - case _ => ; + case _ => ; } case VehicleResponse.PlayerSeatedInVehicle(vehicle, pad) => @@ -2998,7 +3020,9 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con vehicle.PassengerInSeat(player) match { case Some(seatNum) => //participant: observe changes to equipment - (old_weapons ++ old_inventory).foreach { case (_, eguid) => sendResponse(ObjectDeleteMessage(eguid, 0)) } + (old_weapons ++ old_inventory).foreach { + case (_, eguid) => sendResponse(ObjectDeleteMessage(eguid, 0)) + } UpdateWeaponAtSeatPosition(vehicle, seatNum) case None => //observer: observe changes to external equipment @@ -3370,7 +3394,9 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con def handleGamePkt(pkt: PlanetSideGamePacket) = pkt match { case ConnectToWorldRequestMessage(server, token, majorVersion, minorVersion, revision, buildDate, unk) => - log.trace(s"ConnectToWorldRequestMessage: client with versioning $majorVersion.$minorVersion.$revision, $buildDate has sent token $token to the server") + log.trace( + s"ConnectToWorldRequestMessage: client with versioning $majorVersion.$minorVersion.$revision, $buildDate has sent token $token to the server" + ) sendResponse(ChatMsg(ChatMessageType.CMT_CULLWATERMARK, false, "", "", None)) import scala.concurrent.ExecutionContext.Implicits.global clientKeepAlive.cancel() @@ -3579,7 +3605,9 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con _.GUID != vehicle.GUID } case Some(_) => - log.warn(s"BeginZoningMessage: ${player.Name} thought ${player.Sex.pronounSubject} was sitting in a vehicle, but it just evaporated around ${player.Sex.pronounObject}") + log.warn( + s"BeginZoningMessage: ${player.Name} thought ${player.Sex.pronounSubject} was sitting in a vehicle, but it just evaporated around ${player.Sex.pronounObject}" + ) player.VehicleSeated = None (b, List.empty[Vehicle]) case None => @@ -3696,7 +3724,8 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con ToggleTeleportSystem(obj, TelepadLike.AppraiseTeleportationSystem(obj, continent)) } val name = avatar.name - serviceManager.ask(Lookup("hart"))(Timeout(2 seconds)) + serviceManager + .ask(Lookup("hart"))(Timeout(2 seconds)) .onComplete { case Success(LookupResult("hart", ref)) => ref ! HartTimer.Update(continentId, name) @@ -3997,7 +4026,9 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con } case msg @ VehicleSubStateMessage(vehicle_guid, player_guid, vehicle_pos, vehicle_ang, vel, unk1, unk2) => - log.debug(s"VehicleSubState: $vehicle_guid, ${player.Name}_guid, $vehicle_pos, $vehicle_ang, $vel, $unk1, $unk2") + log.debug( + s"VehicleSubState: $vehicle_guid, ${player.Name}_guid, $vehicle_pos, $vehicle_ang, $vel, $unk1, $unk2" + ) case msg @ ProjectileStateMessage(projectile_guid, shot_pos, shot_vel, shot_orient, seq, end, target_guid) => val index = projectile_guid.guid - Projectile.baseUID @@ -4051,19 +4082,19 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con log.warn(s"SpawnRequestMessage: request consumed because ${player.Name} is already respawning ...") } - case _ : SetChatFilterMessage => //msg @ SetChatFilterMessage(send_channel, origin, whitelist) => ; + case _: SetChatFilterMessage => //msg @ SetChatFilterMessage(send_channel, origin, whitelist) => ; - case msg : ChatMsg => + case msg: ChatMsg => chatActor ! ChatActor.Message(msg) - case _ : VoiceHostRequest => + case _: VoiceHostRequest => log.trace(s"VoiceHostRequest: ${player.Name} requested in-game voice chat.") sendResponse(VoiceHostKill()) sendResponse( ChatMsg(ChatMessageType.CMT_OPEN, false, "", "Try our Discord at https://discord.gg/0nRe5TNbTYoUruA4", None) ) - case _ : VoiceHostInfo => + case _: VoiceHostInfo => sendResponse(VoiceHostKill()) case msg @ ChangeAmmoMessage(item_guid, unk1) => @@ -4189,7 +4220,9 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con ) Some(tool) case _ => - log.warn(s"ChangeFireState_Stop: ${player.Name} never started firing item ${item_guid.guid} in the first place?") + log.warn( + s"ChangeFireState_Stop: ${player.Name} never started firing item ${item_guid.guid} in the first place?" + ) None } } @@ -4243,7 +4276,9 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con log.warn(s"DropItem: ${player.Name} wanted to drop a $obj, but that isn't possible") case None => sendResponse(ObjectDeleteMessage(item_guid, 0)) //this is fine; item doesn't exist to the server anyway - log.warn(s"DropItem: ${player.Name} wanted to drop an item ${item_guid.guid}, but it was nowhere to be found") + log.warn( + s"DropItem: ${player.Name} wanted to drop an item ${item_guid.guid}, but it was nowhere to be found" + ) } case msg @ PickupItemMessage(item_guid, player_guid, unk1, unk2) => @@ -4294,7 +4329,9 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con reloadValue } val finalReloadValue = actualReloadValue + currentMagazine - log.info(s"${player.Name} successfully reloaded $reloadValue ${tool.AmmoType} into ${tool.Definition.Name}") + log.info( + s"${player.Name} successfully reloaded $reloadValue ${tool.AmmoType} into ${tool.Definition.Name}" + ) tool.Magazine = finalReloadValue sendResponse(ReloadMessage(item_guid, finalReloadValue, unk1)) continent.AvatarEvents ! AvatarServiceMessage( @@ -4303,7 +4340,9 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con ) } } else { - log.warn(s"ReloadMessage: the ${tool.Definition.Name} under ${player.Name}'s control can not reload (full=$magazineSize, want=$reloadValue)") + log.warn( + s"ReloadMessage: the ${tool.Definition.Name} under ${player.Name}'s control can not reload (full=$magazineSize, want=$reloadValue)" + ) } case (_, Some(_)) => log.warn(s"ReloadMessage: the object that was found for $item_guid was not a Tool") @@ -4401,8 +4440,8 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con (session.account.gm || (player.avatar.vehicle.contains(object_guid) && vehicle.Owner.contains(player.GUID)) || (player.Faction == vehicle.Faction && - (vehicle.Definition.CanBeOwned.nonEmpty && - (vehicle.Owner.isEmpty || continent.GUID(vehicle.Owner.get).isEmpty) || vehicle.Destroyed))) && + (vehicle.Definition.CanBeOwned.nonEmpty && + (vehicle.Owner.isEmpty || continent.GUID(vehicle.Owner.get).isEmpty) || vehicle.Destroyed))) && (vehicle.MountedIn.isEmpty || !vehicle.Seats.values.exists(_.isOccupied)) ) { vehicle.Actor ! Vehicle.Deconstruct() @@ -4503,7 +4542,9 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con ) => ContainableMoveItem(player.Name, source, destination, item, dest) case (None, _, _) => - log.error(s"MoveItem: ${player.Name} wanted to move $item_guid from $source_guid, but could not find source object") + log.error( + s"MoveItem: ${player.Name} wanted to move $item_guid from $source_guid, but could not find source object" + ) case (_, None, _) => log.error( s"MoveItem: ${player.Name} wanted to move $item_guid to $destination_guid, but could not find destination object" @@ -4566,7 +4607,7 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con avatarActor ! AvatarActor.DeactivateImplant(implant.definition.implantType) } case Some(implant) if !implant.initialized => () - case _ => log.error(s"AvatarImplantMessage: ${player.Name} has an unknown implant in $slot") + case _ => log.error(s"AvatarImplantMessage: ${player.Name} has an unknown implant in $slot") } } @@ -4820,7 +4861,9 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con if (llu.Target.GUID == captureTerminal.Owner.GUID) { continent.LocalEvents ! LocalServiceMessage(continent.id, LocalAction.LluCaptured(llu)) } else { - log.info(s"LLU target is not this base. Target GUID: ${llu.Target.GUID} This base: ${captureTerminal.Owner.GUID}") + log.info( + s"LLU target is not this base. Target GUID: ${llu.Target.GUID} This base: ${captureTerminal.Owner.GUID}" + ) } case _ => log.warn("Item in specialItemSlotGuid is not registered with continent or is not a LLU") } @@ -4892,7 +4935,9 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con ) { FindLocalVehicle match { case Some(vehicle) => - log.info(s"${player.Name} is accessing a ${terminal.Definition.Name} for ${player.Sex.possessive} ${vehicle.Definition.Name}") + log.info( + s"${player.Name} is accessing a ${terminal.Definition.Name} for ${player.Sex.possessive} ${vehicle.Definition.Name}" + ) sendResponse( UseItemMessage( avatar_guid, @@ -5049,18 +5094,22 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con case None => ; } - case Some(obj: CaptureFlag) => - // LLU can normally only be picked up the faction that owns it - if (specialItemSlotGuid.isEmpty) { - if(obj.Faction == player.Faction) { - specialItemSlotGuid = Some(obj.GUID) - continent.LocalEvents ! CaptureFlagManager.PickupFlag(obj, player) - } else { - log.warn(s"Player ${player.toString} tried to pick up LLU ${obj.GUID} - ${obj.Faction} that doesn't belong to their faction") + case Some(obj: CaptureFlag) => + // LLU can normally only be picked up the faction that owns it + if (specialItemSlotGuid.isEmpty) { + if (obj.Faction == player.Faction) { + specialItemSlotGuid = Some(obj.GUID) + continent.LocalEvents ! CaptureFlagManager.PickupFlag(obj, player) + } else { + log.warn( + s"Player ${player.toString} tried to pick up LLU ${obj.GUID} - ${obj.Faction} that doesn't belong to their faction" + ) + } + } else if (specialItemSlotGuid.get != obj.GUID) { // Ignore duplicate pickup requests + log.warn( + s"Player ${player.toString} tried to pick up LLU ${obj.GUID} - ${obj.Faction} but their special slot already contains $specialItemSlotGuid" + ) } - } else if(specialItemSlotGuid.get != obj.GUID) { // Ignore duplicate pickup requests - log.warn(s"Player ${player.toString} tried to pick up LLU ${obj.GUID} - ${obj.Faction} but their special slot already contains $specialItemSlotGuid") - } case Some(obj) => CancelZoningProcessWithDescriptiveReason("cancel_use") @@ -5221,7 +5270,8 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con player.Faction match { case PlanetSideEmpire.NC => ToggleMaxSpecialState(enable = false) - case _ => log.warn(s"GenericActionMessage: ${player.Name} tried to cancel an uncancellable MAX special ability") + case _ => + log.warn(s"GenericActionMessage: ${player.Name} tried to cancel an uncancellable MAX special ability") } } else { log.warn(s"GenericActionMessage: ${player.Name} can't handle action code 21") @@ -5274,9 +5324,10 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con CancelZoningProcessWithDescriptiveReason("cancel_use") log.info(s"${player.Name} wishes to load a saved favorite loadout") action match { - case FavoritesAction.Save => avatarActor ! AvatarActor.SaveLoadout(player, loadoutType, label, line) - case FavoritesAction.Delete => avatarActor ! AvatarActor.DeleteLoadout(player, loadoutType, line) - case FavoritesAction.Unknown => log.warn(s"FavoritesRequest: ${player.Name} requested an unknown favorites action") + case FavoritesAction.Save => avatarActor ! AvatarActor.SaveLoadout(player, loadoutType, label, line) + case FavoritesAction.Delete => avatarActor ! AvatarActor.DeleteLoadout(player, loadoutType, line) + case FavoritesAction.Unknown => + log.warn(s"FavoritesRequest: ${player.Name} requested an unknown favorites action") } case msg @ WeaponDelayFireMessage(seq_time, weapon_guid) => ; @@ -5289,7 +5340,9 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con AvatarAction.WeaponDryFire(player.GUID, weapon_guid) ) case _ => - log.warn(s"WeaponDryFire: ${player.Name}'s weapon ${weapon_guid.guid} is either not a weapon or does not exist") + log.warn( + s"WeaponDryFire: ${player.Name}'s weapon ${weapon_guid.guid} is either not a weapon or does not exist" + ) } case msg @ WeaponFireMessage( @@ -5571,9 +5624,9 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con //todo: kick cargo passengers out. To be added after PR #216 is merged obj match { case v: Vehicle - if bailType == BailType.Bailed && - v.SeatPermissionGroup(seat_num).contains(AccessPermissionGroup.Driver) && - v.isFlying => + if bailType == BailType.Bailed && + v.SeatPermissionGroup(seat_num).contains(AccessPermissionGroup.Driver) && + v.isFlying => v.Actor ! Vehicle.Deconstruct(None) //immediate deconstruction case _ => ; } @@ -5674,7 +5727,7 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con log.debug(s"$msg") case msg @ BindPlayerMessage(action, bindDesc, unk1, logging, unk2, unk3, unk4, pos) => - //log.info("BindPlayerMessage: " + msg) + //log.info("BindPlayerMessage: " + msg) case msg @ PlanetsideAttributeMessage(object_guid, attribute_type, attribute_value) => ValidObject(object_guid) match { @@ -5691,41 +5744,45 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con ) //kick players who should not be seated in the vehicle due to permission changes if (allow == VehicleLockState.Locked) { //TODO only important permission atm - vehicle.Seats.foreach { case (seatIndex, seat) => - seat.occupant match { - case Some(tplayer : Player) => - if ( - vehicle.SeatPermissionGroup(seatIndex).contains(group) && tplayer != player - ) { //can not kick self - seat.unmount(tplayer) - tplayer.VehicleSeated = None - continent.VehicleEvents ! VehicleServiceMessage( - continent.id, - VehicleAction.KickPassenger(tplayer.GUID, 4, false, object_guid) - ) - } - case _ => ; // No player seated - } + vehicle.Seats.foreach { + case (seatIndex, seat) => + seat.occupant match { + case Some(tplayer: Player) => + if (vehicle.SeatPermissionGroup(seatIndex).contains(group) && tplayer != player) { //can not kick self + seat.unmount(tplayer) + tplayer.VehicleSeated = None + continent.VehicleEvents ! VehicleServiceMessage( + continent.id, + VehicleAction.KickPassenger(tplayer.GUID, 4, false, object_guid) + ) + } + case _ => ; // No player seated + } } - vehicle.CargoHolds.foreach { case (cargoIndex, hold) => - hold.occupant match { - case Some(cargo) => - if (vehicle.SeatPermissionGroup(cargoIndex).contains(group)) { - //todo: this probably doesn't work for passengers within the cargo vehicle - // Instruct client to start bail dismount procedure - self ! DismountVehicleCargoMsg(player.GUID, cargo.GUID, true, false, false) - } - case None => ; // No vehicle in cargo - } + vehicle.CargoHolds.foreach { + case (cargoIndex, hold) => + hold.occupant match { + case Some(cargo) => + if (vehicle.SeatPermissionGroup(cargoIndex).contains(group)) { + //todo: this probably doesn't work for passengers within the cargo vehicle + // Instruct client to start bail dismount procedure + self ! DismountVehicleCargoMsg(player.GUID, cargo.GUID, true, false, false) + } + case None => ; // No vehicle in cargo + } } } case None => ; } } else { - log.warn(s"PlanetsideAttribute: vehicle attributes - unsupported change on vehicle $object_guid - $attribute_type, ${player.Name}") + log.warn( + s"PlanetsideAttribute: vehicle attributes - unsupported change on vehicle $object_guid - $attribute_type, ${player.Name}" + ) } } else { - log.warn(s"PlanetsideAttribute: vehicle attributes - ${player.Name} does not own vehicle ${vehicle.GUID} and can not change it") + log.warn( + s"PlanetsideAttribute: vehicle attributes - ${player.Name} does not own vehicle ${vehicle.GUID} and can not change it" + ) } // Cosmetics options @@ -5778,7 +5835,9 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con Some(TargetInfo(player.GUID, health, armor)) case _ => - log.warn(s"TargetingImplantRequest: the info that ${player.Name} requested for target ${x.target_guid} is not for a player") + log.warn( + s"TargetingImplantRequest: the info that ${player.Name} requested for target ${x.target_guid} is not for a player" + ) None } }) @@ -6514,16 +6573,16 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con //handle inventory contents box.Capacity = if (sumReloadValue <= fullMagazine) { - sumReloadValue - } else { - val splitReloadAmmo: Int = sumReloadValue - fullMagazine - log.trace( - s"PerformToolAmmoChange: ${player.Name} takes ${originalBoxCapacity - splitReloadAmmo} from a box of $originalBoxCapacity $requestedAmmoType ammo" - ) - val boxForInventory = AmmoBox(box.Definition, splitReloadAmmo) - continent.tasks ! stowNewFunc(boxForInventory) - fullMagazine - } + sumReloadValue + } else { + val splitReloadAmmo: Int = sumReloadValue - fullMagazine + log.trace( + s"PerformToolAmmoChange: ${player.Name} takes ${originalBoxCapacity - splitReloadAmmo} from a box of $originalBoxCapacity $requestedAmmoType ammo" + ) + val boxForInventory = AmmoBox(box.Definition, splitReloadAmmo) + continent.tasks ! stowNewFunc(boxForInventory) + fullMagazine + } sendResponse( InventoryStateMessage(box.GUID, tool.GUID, box.Capacity) ) //should work for both players and vehicles @@ -6637,12 +6696,12 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con else { xs.map(_.obj.asInstanceOf[Tool].Magazine).sum } val sumReloadValue: Int = box.Magazine + tailReloadValue val actualReloadValue = if (sumReloadValue <= 3) { - RemoveOldEquipmentFromInventory(player)(x.obj) - sumReloadValue - } else { - ModifyAmmunition(player)(box.AmmoSlot.Box, 3 - tailReloadValue) - 3 - } + RemoveOldEquipmentFromInventory(player)(x.obj) + sumReloadValue + } else { + ModifyAmmunition(player)(box.AmmoSlot.Box, 3 - tailReloadValue) + 3 + } log.info(s"${player.Name} found $actualReloadValue more $ammoType grenades to throw") ModifyAmmunition(player)( tool.AmmoSlot.Box, @@ -6859,27 +6918,33 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con case obj: Hackable if obj.HackedBy.nonEmpty => //sync hack state amenity.Definition match { - case GlobalDefinitions.capture_terminal => - SendPlanetsideAttributeMessage( - amenity.GUID, - PlanetsideAttributeEnum.ControlConsoleHackUpdate, - HackCaptureActor.GetHackUpdateAttributeValue(amenity.asInstanceOf[CaptureTerminal], isResecured = false)) - case _ => - HackObject(amenity.GUID, 1114636288L, 8L) //generic hackable object - } + case GlobalDefinitions.capture_terminal => + SendPlanetsideAttributeMessage( + amenity.GUID, + PlanetsideAttributeEnum.ControlConsoleHackUpdate, + HackCaptureActor.GetHackUpdateAttributeValue(amenity.asInstanceOf[CaptureTerminal], isResecured = false) + ) + case _ => + HackObject(amenity.GUID, 1114636288L, 8L) //generic hackable object + } // sync capture flags case llu: CaptureFlag => // Create LLU - sendResponse(ObjectCreateMessage( - llu.Definition.ObjectId, - llu.GUID, - llu.Definition.Packet.ConstructorData(llu).get - )) + sendResponse( + ObjectCreateMessage( + llu.Definition.ObjectId, + llu.GUID, + llu.Definition.Packet.ConstructorData(llu).get + ) + ) // Attach it to a player if it has a carrier if (llu.Carrier.nonEmpty) { - continent.LocalEvents ! LocalServiceMessage(continent.id, LocalAction.SendPacket(ObjectAttachMessage(llu.Carrier.get.GUID, llu.GUID, 252))) + continent.LocalEvents ! LocalServiceMessage( + continent.id, + LocalAction.SendPacket(ObjectAttachMessage(llu.Carrier.get.GUID, llu.GUID, 252)) + ) } case _ => ; } @@ -6926,7 +6991,11 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con * @param attribute_number The attribute number * @param attribute_value The attribute value */ - def SendPlanetsideAttributeMessage(target_guid: PlanetSideGUID, attribute_number: PlanetsideAttributeEnum, attribute_value: Long): Unit = { + def SendPlanetsideAttributeMessage( + target_guid: PlanetSideGUID, + attribute_number: PlanetsideAttributeEnum, + attribute_value: Long + ): Unit = { sendResponse(PlanetsideAttributeMessage(target_guid, attribute_number, attribute_value)) } @@ -7462,7 +7531,7 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con sendResponse(DisconnectMessage("RequestSanctuaryZoneSpawn: player is already in sanctuary.")) } else { continent.GUID(player.VehicleSeated) match { - case Some(obj : Vehicle) if !obj.Destroyed => + case Some(obj: Vehicle) if !obj.Destroyed => cluster ! ICS.GetRandomSpawnPoint( Zones.sanctuaryZoneNumber(player.Faction), player.Faction, @@ -7528,7 +7597,9 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con case _: Vehicle => terminal.Actor ! CommonMessages.Use(player, Some((target, continent.VehicleEvents))) case _ => - log.error(s"StartUsingProximityUnit: ${player.Name}, this ${terminal.Definition.Name} can not deal with target $target") + log.error( + s"StartUsingProximityUnit: ${player.Name}, this ${terminal.Definition.Name} can not deal with target $target" + ) } terminal.Definition match { case GlobalDefinitions.adv_med_terminal | GlobalDefinitions.medical_terminal => @@ -7561,7 +7632,7 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con */ def StopUsingProximityUnit(terminal: Terminal with ProximityUnit): Unit = { val term_guid = terminal.GUID - val targets = FindProximityUnitTargetsInScope(terminal) + val targets = FindProximityUnitTargetsInScope(terminal) if (targets.nonEmpty) { if (usingMedicalTerminal.contains(term_guid)) { usingMedicalTerminal = None @@ -7802,10 +7873,10 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con * @return the projectile */ def ResolveProjectileInteraction( - projectile_guid: PlanetSideGUID, - resolution: DamageResolution.Value, - target: PlanetSideGameObject with FactionAffinity with Vitality, - pos: Vector3 + projectile_guid: PlanetSideGUID, + resolution: DamageResolution.Value, + target: PlanetSideGameObject with FactionAffinity with Vitality, + pos: Vector3 ): Option[DamageInteraction] = { FindProjectileEntry(projectile_guid) match { case Some(projectile) => @@ -7824,11 +7895,11 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con * @return a copy of the projectile */ def ResolveProjectileInteraction( - projectile: Projectile, - index: Int, - resolution: DamageResolution.Value, - target: PlanetSideGameObject with FactionAffinity with Vitality, - pos: Vector3 + projectile: Projectile, + index: Int, + resolution: DamageResolution.Value, + target: PlanetSideGameObject with FactionAffinity with Vitality, + pos: Vector3 ): Option[DamageInteraction] = { if (!projectiles(index).contains(projectile)) { log.error(s"expected projectile could not be found at $index; can not resolve") @@ -7845,10 +7916,10 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con * @return a copy of the projectile */ def ResolveProjectileInteraction( - projectile: Projectile, - resolution: DamageResolution.Value, - target: PlanetSideGameObject with FactionAffinity with Vitality, - pos: Vector3 + projectile: Projectile, + resolution: DamageResolution.Value, + target: PlanetSideGameObject with FactionAffinity with Vitality, + pos: Vector3 ): Option[DamageInteraction] = { if (projectile.isMiss) { log.warn("expected projectile was already counted as a missed shot; can not resolve any further") @@ -8248,7 +8319,9 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con } else { player.Find(tool) match { case Some(newIndex) => - log.warn(s"$logDecorator: ${player.Name} was looking for an item in his hand $index, but item was found at $newIndex instead") + log.warn( + s"$logDecorator: ${player.Name} was looking for an item in his hand $index, but item was found at $newIndex instead" + ) player.Slot(newIndex).Equipment = None true case None => @@ -8433,16 +8506,17 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con val events = continent.AvatarEvents val zoneId = continent.id (player.Inventory.Items ++ player.HolsterItems()) - .collect { case InventoryItem(obj: BoomerTrigger, index) => - player.Slot(index).Equipment = None - sendResponse(ObjectDeleteMessage(obj.GUID, 0)) - if (player.HasGUID && player.VisibleSlots.contains(index)) { - events ! AvatarServiceMessage( - zoneId, - AvatarAction.ObjectDelete(player.GUID, obj.GUID) - ) - } - obj + .collect { + case InventoryItem(obj: BoomerTrigger, index) => + player.Slot(index).Equipment = None + sendResponse(ObjectDeleteMessage(obj.GUID, 0)) + if (player.HasGUID && player.VisibleSlots.contains(index)) { + events ! AvatarServiceMessage( + zoneId, + AvatarAction.ObjectDelete(player.GUID, obj.GUID) + ) + } + obj } } @@ -8626,7 +8700,7 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con val msg: String = s"${player.Name} is driving a ${vehicle.Definition.Name}" log.info(msg) log.debug(s"LoadZoneInVehicleAsDriver: $msg") - val manifest = vehicle.PrepareGatingManifest() + val manifest = vehicle.PrepareGatingManifest() val pguid = player.GUID val toChannel = manifest.file val topLevel = interstellarFerryTopLevelGUID.getOrElse(vehicle.GUID) @@ -8637,7 +8711,9 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con manifest.cargo.foreach { case ManifestPassengerEntry("MISSING_DRIVER", index) => val cargo = vehicle.CargoHolds(index).occupant.get - log.warn(s"LoadZoneInVehicleAsDriver: ${player.Name} must eject cargo in hold $index; vehicle is missing driver") + log.warn( + s"LoadZoneInVehicleAsDriver: ${player.Name} must eject cargo in hold $index; vehicle is missing driver" + ) CargoBehavior.HandleVehicleCargoDismount(cargo.GUID, cargo, vehicle.GUID, vehicle, false, false, true) case entry => val cargo = vehicle.CargoHolds(entry.mount).occupant.get @@ -8758,14 +8834,16 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con case hold if hold.isOccupied => val cargo = hold.occupant.get cargo.Continent = toZoneId - //point to the cargo vehicle to instigate cargo vehicle driver transportation + //point to the cargo vehicle to instigate cargo vehicle driver transportation // galaxyService ! GalaxyServiceMessage( // toChannel, // GalaxyAction.TransferPassenger(player_guid, toChannel, vehicle, topLevel, manifest) // ) } case None => - log.error(s"LoadZoneTransferPassengerMessages: ${player.Name} expected a manifest for zone transfer; got nothing") + log.error( + s"LoadZoneTransferPassengerMessages: ${player.Name} expected a manifest for zone transfer; got nothing" + ) } } @@ -9522,18 +9600,18 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con s"WeaponFireMessage: ${player.Name}'s ${projectile_info.Name} is a remote projectile" ) continent.tasks ! (if (projectile.HasGUID) { - continent.AvatarEvents ! AvatarServiceMessage( - continent.id, - AvatarAction.ProjectileExplodes( - player.GUID, - projectile.GUID, - projectile - ) - ) - ReregisterProjectile(projectile) - } else { - RegisterProjectile(projectile) - }) + continent.AvatarEvents ! AvatarServiceMessage( + continent.id, + AvatarAction.ProjectileExplodes( + player.GUID, + projectile.GUID, + projectile + ) + ) + ReregisterProjectile(projectile) + } else { + RegisterProjectile(projectile) + }) } projectilesToCleanUp(projectileIndex) = false diff --git a/src/main/scala/net/psforever/services/local/LocalService.scala b/src/main/scala/net/psforever/services/local/LocalService.scala index 23115762..8214bfe1 100644 --- a/src/main/scala/net/psforever/services/local/LocalService.scala +++ b/src/main/scala/net/psforever/services/local/LocalService.scala @@ -18,11 +18,14 @@ import net.psforever.types.{PlanetSideGUID, Vector3} import scala.concurrent.duration.{Duration, _} class LocalService(zone: Zone) extends Actor { - private val doorCloser = context.actorOf(Props[DoorCloseActor](), s"${zone.id}-local-door-closer") - private val hackClearer = context.actorOf(Props[HackClearActor](), s"${zone.id}-local-hack-clearer") - private val hackCapturer = context.actorOf(Props(classOf[HackCaptureActor], zone.tasks), s"${zone.id}-local-hack-capturer") - private val captureFlagManager = context.actorOf(Props(classOf[CaptureFlagManager], zone.tasks, zone), s"${zone.id}-local-capture-flag-manager") - private val engineer = context.actorOf(Props(classOf[DeployableRemover], zone.tasks), s"${zone.id}-deployable-remover-agent") + private val doorCloser = context.actorOf(Props[DoorCloseActor](), s"${zone.id}-local-door-closer") + private val hackClearer = context.actorOf(Props[HackClearActor](), s"${zone.id}-local-hack-clearer") + private val hackCapturer = + context.actorOf(Props(classOf[HackCaptureActor], zone.tasks), s"${zone.id}-local-hack-capturer") + private val captureFlagManager = + context.actorOf(Props(classOf[CaptureFlagManager], zone.tasks, zone), s"${zone.id}-local-capture-flag-manager") + private val engineer = + context.actorOf(Props(classOf[DeployableRemover], zone.tasks), s"${zone.id}-deployable-remover-agent") private val teleportDeployment: ActorRef = context.actorOf(Props[RouterTelepadActivation](), s"${zone.id}-telepad-activate-agent") private[this] val log = org.log4s.getLogger @@ -83,7 +86,11 @@ class LocalService(zone: Zone) extends Actor { ) case LocalAction.HackClear(player_guid, target, unk1, unk2) => LocalEvents.publish( - LocalServiceResponse(s"/$forChannel/Local", player_guid, LocalResponse.SendHackMessageHackCleared(target.GUID, unk1, unk2)) + LocalServiceResponse( + s"/$forChannel/Local", + player_guid, + LocalResponse.SendHackMessageHackCleared(target.GUID, unk1, unk2) + ) ) case LocalAction.HackTemporarily(player_guid, _, target, unk1, duration, unk2) => hackClearer ! HackClearActor.ObjectIsHacked(target, zone, unk1, unk2, duration) @@ -281,6 +288,13 @@ class LocalService(zone: Zone) extends Actor { //response from HackClearActor case HackClearActor.SendHackMessageHackCleared(target_guid, _, unk1, unk2) => log.info(s"Clearing hack for $target_guid") + LocalEvents.publish( + LocalServiceResponse( + s"/${zone.id}/Local", + Service.defaultPlayerGUID, + LocalResponse.SendHackMessageHackCleared(target_guid, unk1, unk2) + ) + ) //message from ProximityTerminalControl case Terminal.StartProximityEffect(terminal) => @@ -418,13 +432,9 @@ class LocalService(zone: Zone) extends Actor { sender() ! Vitality.DamageResolution(target, cause) // Forward all CaptureFlagManager messages - case msg @ - (CaptureFlagManager.SpawnCaptureFlag(_, _, _) - | CaptureFlagManager.PickupFlag(_, _) - | CaptureFlagManager.DropFlag(_) - | CaptureFlagManager.Captured(_) - | CaptureFlagManager.Lost(_, _) - | CaptureFlagManager) => + case msg @ (CaptureFlagManager.SpawnCaptureFlag(_, _, _) | CaptureFlagManager.PickupFlag(_, _) | + CaptureFlagManager.DropFlag(_) | CaptureFlagManager.Captured(_) | CaptureFlagManager.Lost(_, _) | + CaptureFlagManager) => captureFlagManager.forward(msg) case msg => From 25bb2cc5acbb06a2fd052fa4c1d8b9d2b4e647f3 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Sun, 18 Apr 2021 00:48:03 +0000 Subject: [PATCH 11/13] Update dependency com.github.pureconfig:pureconfig to v0.15.0 --- build.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.sbt b/build.sbt index a2ffa89a..98af02a9 100644 --- a/build.sbt +++ b/build.sbt @@ -69,7 +69,7 @@ lazy val psforeverSettings = Seq( "org.flywaydb" % "flyway-core" % "7.8.1", "org.postgresql" % "postgresql" % "42.2.19", "com.typesafe" % "config" % "1.4.1", - "com.github.pureconfig" %% "pureconfig" % "0.14.1", + "com.github.pureconfig" %% "pureconfig" % "0.15.0", "com.beachape" %% "enumeratum" % "1.6.1", "joda-time" % "joda-time" % "2.10.10", "commons-io" % "commons-io" % "2.8.0", From 490e6244e7d056cc213d5f6aea6731a15e5785df Mon Sep 17 00:00:00 2001 From: Jakob Gillich Date: Sun, 18 Apr 2021 07:47:20 +0200 Subject: [PATCH 12/13] Correctly set active=false when deinitializing implants Plus a minor logging improvement in MA --- .../net/psforever/actors/net/MiddlewareActor.scala | 6 +++--- .../net/psforever/actors/session/AvatarActor.scala | 11 +++++------ 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/main/scala/net/psforever/actors/net/MiddlewareActor.scala b/src/main/scala/net/psforever/actors/net/MiddlewareActor.scala index c97ff2bf..a5947987 100644 --- a/src/main/scala/net/psforever/actors/net/MiddlewareActor.scala +++ b/src/main/scala/net/psforever/actors/net/MiddlewareActor.scala @@ -297,7 +297,7 @@ class MiddlewareActor( log.warn(s"Unexpected packet type $packet in start (before crypto)") Behaviors.same } - case Failure(_) => + case Failure(unmarshalError) => // There is a special case where no crypto is being used. // The only packet coming through looks like PingMsg. This is a hardcoded // feature of the client @ 0x005FD618 @@ -318,8 +318,8 @@ class MiddlewareActor( log.error(s"Unexpected non-crypto packet type $packet in start") Behaviors.same } - case Failure(e) => - log.error(s"Could not decode packet in start: $e") + case Failure(decodeError) => + log.error(s"Could not decode packet in start: '$unmarshalError' / '$decodeError'") Behaviors.same } } diff --git a/src/main/scala/net/psforever/actors/session/AvatarActor.scala b/src/main/scala/net/psforever/actors/session/AvatarActor.scala index 1020284d..a347b336 100644 --- a/src/main/scala/net/psforever/actors/session/AvatarActor.scala +++ b/src/main/scala/net/psforever/actors/session/AvatarActor.scala @@ -784,7 +784,7 @@ class AvatarActor( } match { case Some((implant, slot)) => if (!implant.initialized) { - log.error(s"requested activation of uninitialized implant $implant") + log.warn(s"requested activation of uninitialized implant $implantType") } else if ( !consumeStamina(implant.definition.ActivationStaminaCost) || avatar.stamina < implant.definition.StaminaCost @@ -877,7 +877,7 @@ class AvatarActor( val totalStamina = math.min(avatar.maxStamina, avatar.stamina + stamina) val fatigued = if (avatar.fatigued && totalStamina >= 20) { avatar.implants.zipWithIndex.foreach { - case (Some(implant), slot) => + case (Some(_), slot) => sessionActor ! SessionActor.SendResponse( AvatarImplantMessage(session.get.player.GUID, ImplantAction.OutOfStamina, slot, 0) ) @@ -1103,16 +1103,15 @@ class AvatarActor( AvatarImplantMessage(session.get.player.GUID, ImplantAction.Initialization, slot, 0) ) ) - Some(implant.copy(initialized = false)) + Some(implant.copy(initialized = false, active = false)) case (None, _) => None }) } def deactivateImplant(implantType: ImplantType): Unit = { - val res = avatar.implants.zipWithIndex.collectFirst { + avatar.implants.zipWithIndex.collectFirst { case (Some(implant), index) if implant.definition.implantType == implantType => (implant, index) - } - res match { + } match { case Some((implant, slot)) => implantTimers(slot).cancel() avatar = avatar.copy( From 2dc1b5736a24799e6a7c0082b133fe92359cd674 Mon Sep 17 00:00:00 2001 From: Jakob Gillich Date: Sun, 18 Apr 2021 08:22:47 +0200 Subject: [PATCH 13/13] Fix implant auto activation not always working --- .../actors/session/AvatarActor.scala | 22 +++++++------------ .../actors/session/SessionActor.scala | 7 +++--- 2 files changed, 11 insertions(+), 18 deletions(-) diff --git a/src/main/scala/net/psforever/actors/session/AvatarActor.scala b/src/main/scala/net/psforever/actors/session/AvatarActor.scala index a347b336..249e9af2 100644 --- a/src/main/scala/net/psforever/actors/session/AvatarActor.scala +++ b/src/main/scala/net/psforever/actors/session/AvatarActor.scala @@ -846,12 +846,6 @@ class AvatarActor( case other => other }) - // automatic targeting implant activation is a client side feature - // For some reason it doesn't always work with 100% reliability, so we're also activating it server side - // Must be delayed by a bit or the client will toggle it off again - if (implantType == ImplantType.Targeting) { - context.scheduleOnce(2.seconds, context.self, ActivateImplant(implantType)) - } case None => log.error(s"set initialized called for unknown implant $implantType") } @@ -1071,14 +1065,6 @@ class AvatarActor( ) ) - // Start client side initialization timer, visible on the character screen - // Progress accumulates according to the client's knowledge of the implant initialization time - // What is normally a 60s timer that is set to 120s on the server will still visually update as if 60s - session.get.zone.AvatarEvents ! AvatarServiceMessage( - avatar.name, - AvatarAction.SendResponse(Service.defaultPlayerGUID, ActionProgressMessage(slot + 6, 0)) - ) - implantTimers.get(slot).foreach(_.cancel()) implantTimers(slot) = context.scheduleOnce( implant.definition.InitializationDuration.seconds, @@ -1086,6 +1072,14 @@ class AvatarActor( SetImplantInitialized(implant.definition.implantType) ) + // Start client side initialization timer, visible on the character screen + // Progress accumulates according to the client's knowledge of the implant initialization time + // What is normally a 60s timer that is set to 120s on the server will still visually update as if 60s\ + session.get.zone.AvatarEvents ! AvatarServiceMessage( + avatar.name, + AvatarAction.SendResponse(Service.defaultPlayerGUID, ActionProgressMessage(slot + 6, 0)) + ) + case (None, _) => ; } } diff --git a/src/main/scala/net/psforever/actors/session/SessionActor.scala b/src/main/scala/net/psforever/actors/session/SessionActor.scala index 7897b278..e714eeb3 100644 --- a/src/main/scala/net/psforever/actors/session/SessionActor.scala +++ b/src/main/scala/net/psforever/actors/session/SessionActor.scala @@ -4600,14 +4600,13 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con if (action == ImplantAction.Activation) { CancelZoningProcessWithDescriptiveReason("cancel_implant") avatar.implants(slot) match { - case Some(implant) if implant.initialized => - if (!implant.active) { + case Some(implant) => + if (status == 1) { avatarActor ! AvatarActor.ActivateImplant(implant.definition.implantType) } else { avatarActor ! AvatarActor.DeactivateImplant(implant.definition.implantType) } - case Some(implant) if !implant.initialized => () - case _ => log.error(s"AvatarImplantMessage: ${player.Name} has an unknown implant in $slot") + case _ => log.error(s"AvatarImplantMessage: ${player.Name} has an unknown implant in $slot") } }