diff --git a/src/main/scala/net/psforever/actors/session/AvatarActor.scala b/src/main/scala/net/psforever/actors/session/AvatarActor.scala index 249e9af2a..3f2ec18ba 100644 --- a/src/main/scala/net/psforever/actors/session/AvatarActor.scala +++ b/src/main/scala/net/psforever/actors/session/AvatarActor.scala @@ -721,14 +721,14 @@ class AvatarActor( Behaviors.same case UpdatePurchaseTime(definition, time) => - if (!Avatar.purchaseCooldowns.contains(definition)) { - // TODO only send for items with cooldowns + //only send for items with cooldowns + Avatar.purchaseCooldowns.get(definition) match { + case Some(cooldown) => + // TODO save to db + avatar = avatar.copy(purchaseTimes = avatar.purchaseTimes.updated(definition.Name, time)) + updatePurchaseTimer(definition.Name, cooldown.toSeconds, unk1 = true) + case None => ; //log.warn(s"UpdatePurchaseTime message for item '${definition.Name}' without cooldown") - } else { - // TODO save to db - avatar = avatar.copy(purchaseTimes = avatar.purchaseTimes.updated(definition.Name, time)) - // we could be more selective and only send what changed, but it doesn't hurt to refresh everything - context.self ! RefreshPurchaseTimes() } Behaviors.same @@ -740,38 +740,7 @@ class AvatarActor( Behaviors.same case RefreshPurchaseTimes() => - avatar.purchaseTimes.foreach { - case (name, purchaseTime) => - val secondsSincePurchase = Seconds.secondsBetween(purchaseTime, LocalDateTime.now()).getSeconds - - Avatar.purchaseCooldowns.find(_._1.Name == name) match { - case Some((obj, cooldown)) if cooldown.toSeconds - secondsSincePurchase > 0 => - val faction: String = avatar.faction.toString.toLowerCase - val name = obj match { - case GlobalDefinitions.trhev_dualcycler | GlobalDefinitions.nchev_scattercannon | - GlobalDefinitions.vshev_quasar => - s"${faction}hev_antipersonnel" - case GlobalDefinitions.trhev_pounder | GlobalDefinitions.nchev_falcon | - GlobalDefinitions.vshev_comet => - s"${faction}hev_antivehicular" - case GlobalDefinitions.trhev_burster | GlobalDefinitions.nchev_sparrow | - GlobalDefinitions.vshev_starfire => - s"${faction}hev_antiaircraft" - case _ => obj.Name - } - - sessionActor ! SessionActor.SendResponse( - AvatarVehicleTimerMessage( - session.get.player.GUID, - name, - cooldown.toSeconds - secondsSincePurchase, - unk1 = true - ) - ) - - case _ => ; - } - } + refreshPurchaseTimes(avatar.purchaseTimes.keys.toSet) Behaviors.same case SetVehicle(vehicle) => @@ -1293,8 +1262,8 @@ class AvatarActor( loadout.items.split("/").foreach { case value => val (objectType, objectIndex, objectId, toolAmmo) = value.split(",") match { - case Array(a, b, c) => (a, b.toInt, c.toInt, None) - case Array(a, b, c, d) => (a, b.toInt, c.toInt, Some(d)) + case Array(a, b: String, c: String) => (a, b.toInt, c.toInt, None) + case Array(a, b: String, c: String, d) => (a, b.toInt, c.toInt, Some(d)) } objectType match { @@ -1317,9 +1286,9 @@ class AvatarActor( } toolAmmo foreach { toolAmmo => - toolAmmo.split("_").drop(1).foreach { value => + toolAmmo.toString.split("_").drop(1).foreach { value => val (ammoSlots, ammoTypeIndex, ammoBoxDefinition) = value.split("-") match { - case Array(a, b, c) => (a.toInt, b.toInt, c.toInt) + case Array(a: String, b: String, c: String) => (a.toInt, b.toInt, c.toInt) } doll.Slot(objectIndex).Equipment.get.asInstanceOf[Tool].AmmoSlots(ammoSlots).AmmoTypeIndex = ammoTypeIndex @@ -1367,4 +1336,48 @@ class AvatarActor( }) } + def refreshPurchaseTimes(keys: Set[String]): Unit = { + var keysToDrop: Seq[String] = Nil + keys.foreach { key => + avatar.purchaseTimes.find { case (name, _) => name.equals(key) } match { + case Some((name, purchaseTime)) => + val secondsSincePurchase = Seconds.secondsBetween(purchaseTime, LocalDateTime.now()).getSeconds + Avatar.purchaseCooldowns.find(_._1.Name == name) match { + case Some((obj, cooldown)) if cooldown.toSeconds - secondsSincePurchase > 0 => + val faction : String = avatar.faction.toString.toLowerCase + val name = obj match { + case GlobalDefinitions.trhev_dualcycler | + GlobalDefinitions.nchev_scattercannon | + GlobalDefinitions.vshev_quasar => + s"${faction}hev_antipersonnel" + case GlobalDefinitions.trhev_pounder | + GlobalDefinitions.nchev_falcon | + GlobalDefinitions.vshev_comet => + s"${faction}hev_antivehicular" + case GlobalDefinitions.trhev_burster | + GlobalDefinitions.nchev_sparrow | + GlobalDefinitions.vshev_starfire => + s"${faction}hev_antiaircraft" + case _ => + obj.Name + } + updatePurchaseTimer(name, cooldown.toSeconds - secondsSincePurchase, unk1 = true) + + case _ => + keysToDrop = keysToDrop :+ key //key has timed-out + } + case _ => ; + } + } + if (keysToDrop.nonEmpty) { + avatar = avatar.copy(purchaseTimes = avatar.purchaseTimes.removedAll(keysToDrop)) + } + } + + def updatePurchaseTimer(name: String, time: Long, unk1: Boolean): Unit = { + //TODO? unk1 is: vehicles = true, everything else = false + sessionActor ! SessionActor.SendResponse( + AvatarVehicleTimerMessage(session.get.player.GUID, name, time, unk1 = true) + ) + } } diff --git a/src/main/scala/net/psforever/actors/session/SessionActor.scala b/src/main/scala/net/psforever/actors/session/SessionActor.scala index e714eeb39..1b2558885 100644 --- a/src/main/scala/net/psforever/actors/session/SessionActor.scala +++ b/src/main/scala/net/psforever/actors/session/SessionActor.scala @@ -1313,7 +1313,7 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con case PlayerLoaded(tplayer) => //same zone - log.info(s"Player ${tplayer.Name} will respawn") + log.info(s"${tplayer.Name} will respawn") tplayer.avatar = avatar session = session.copy(player = tplayer) setupAvatarFunc() @@ -2504,7 +2504,7 @@ 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 { + log.info(s"${player.Name} mounts the ${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" @@ -2703,14 +2703,6 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con case Some(_) => sendResponse(ItemTransactionResultMessage(msg.terminal_guid, TransactionType.Buy, success = false)) case None => - avatarActor ! AvatarActor.UpdatePurchaseTime(vehicle.Definition) - Avatar.purchaseCooldowns.get(vehicle.Definition) match { - case Some(cooldown) => - sendResponse( - AvatarVehicleTimerMessage(tplayer.GUID, vehicle.Definition.Name, cooldown.toSeconds, unk1 = true) - ) - case None => ; - } val pad = continent.GUID(padGuid).get.asInstanceOf[VehicleSpawnPad] vehicle.Faction = tplayer.Faction vehicle.Position = pad.Position @@ -2972,6 +2964,7 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con } sendResponse(PlanetsideAttributeMessage(vehicle_guid, 22, 1L)) //mount points off sendResponse(PlanetsideAttributeMessage(player.GUID, 21, vehicle_guid)) //ownership + avatarActor ! AvatarActor.UpdatePurchaseTime(vehicle.Definition) vehicle.MountPoints.find { case (_, mp) => mp.seatIndex == 0 } match { case Some((mountPoint, _)) => vehicle.Actor ! Mountable.TryMount(player, mountPoint) case _ => ;