From 8dcf678045d99e923fdd9869f3f6ab4a1bb321e3 Mon Sep 17 00:00:00 2001 From: Resaec Date: Sun, 31 Aug 2025 00:01:58 +0200 Subject: [PATCH] add Outfit Rank / Title updates --- .../actors/session/normal/GeneralLogic.scala | 3 +- .../support/SessionOutfitHandlers.scala | 141 ++++++++++++++---- 2 files changed, 116 insertions(+), 28 deletions(-) diff --git a/src/main/scala/net/psforever/actors/session/normal/GeneralLogic.scala b/src/main/scala/net/psforever/actors/session/normal/GeneralLogic.scala index b16386d78..79c335505 100644 --- a/src/main/scala/net/psforever/actors/session/normal/GeneralLogic.scala +++ b/src/main/scala/net/psforever/actors/session/normal/GeneralLogic.scala @@ -834,8 +834,7 @@ class GeneralLogic(val ops: GeneralOperations, implicit val context: ActorContex SessionOutfitHandlers.HandleOutfitMotd(zones, message, player) case OutfitRequest(_, OutfitRequestAction.Ranks(List(r1, r2, r3, r4, r5, r6, r7, r8))) => - // update db - //sendResponse(OutfitEvent(6418, Unk2(OutfitInfo(player.outfit_name, 0, 0, 1, OutfitRankNames(r1.getOrElse(""), r2.getOrElse(""), r3.getOrElse(""), r4.getOrElse(""), r5.getOrElse(""), r6.getOrElse(""), r7.getOrElse(""), r8.getOrElse("")), "Welcome to the first PSForever Outfit!", 0, unk11=true, 0, 8888888, 0, 0, 0)))) + SessionOutfitHandlers.HandleOutfitRank(zones, List(r1, r2, r3, r4, r5, r6, r7, r8), player) case OutfitRequest(_, OutfitRequestAction.Unk3(true)) => SessionOutfitHandlers.HandleViewOutfitWindow(zones, player, player.outfit_id) diff --git a/src/main/scala/net/psforever/actors/session/support/SessionOutfitHandlers.scala b/src/main/scala/net/psforever/actors/session/support/SessionOutfitHandlers.scala index b3bedc365..47ba310c9 100644 --- a/src/main/scala/net/psforever/actors/session/support/SessionOutfitHandlers.scala +++ b/src/main/scala/net/psforever/actors/session/support/SessionOutfitHandlers.scala @@ -437,33 +437,33 @@ object SessionOutfitHandlers { // send to all online players in outfit val outfit_event = OutfitEvent( - outfit_id, - Unk2( - OutfitInfo( - outfit_name = outfit.name, - outfit_points1 = totalPoints, - outfit_points2 = totalPoints, - member_count = memberCount, - outfit_rank_names = OutfitRankNames( - outfit.rank0.getOrElse(""), - outfit.rank1.getOrElse(""), - outfit.rank2.getOrElse(""), - outfit.rank3.getOrElse(""), - outfit.rank4.getOrElse(""), - outfit.rank5.getOrElse(""), - outfit.rank6.getOrElse(""), - outfit.rank7.getOrElse(""), - ), - motd = outfit.motd.getOrElse(""), - unk10 = 0, - unk11 = true, - unk12 = 0, - created_timestamp = outfit.created.atZone(java.time.ZoneOffset.UTC).toInstant.toEpochMilli / 1000, - unk23 = 0, - unk24 = 0, - unk25 = 0 - ) + outfit_id, + Unk2( + OutfitInfo( + outfit_name = outfit.name, + outfit_points1 = totalPoints, + outfit_points2 = totalPoints, + member_count = memberCount, + outfit_rank_names = OutfitRankNames( + outfit.rank0.getOrElse(""), + outfit.rank1.getOrElse(""), + outfit.rank2.getOrElse(""), + outfit.rank3.getOrElse(""), + outfit.rank4.getOrElse(""), + outfit.rank5.getOrElse(""), + outfit.rank6.getOrElse(""), + outfit.rank7.getOrElse(""), + ), + motd = outfit.motd.getOrElse(""), + unk10 = 0, + unk11 = true, + unk12 = 0, + created_timestamp = outfit.created.atZone(java.time.ZoneOffset.UTC).toInstant.toEpochMilli / 1000, + unk23 = 0, + unk24 = 0, + unk25 = 0 ) + ) ) zones.foreach(zone => { @@ -481,6 +481,65 @@ object SessionOutfitHandlers { // S >> C OutfitEvent(Unk2, 529744, Unk2(OutfitInfo(PlanetSide_Forever_Vanu, 0, 0, 3, OutfitRankNames(, , , , , , , ), Vanu outfit for the planetside forever project! -find out more about the PSEMU project at PSforever.net, 0, 1, 0, 1458331641, 0, 0, 0))) } + def HandleOutfitRank(zones: Seq[Zone], list: List[Option[String]], player: Player): Unit = { + + val outfit_id = player.outfit_id + + val outfitDetails = for { + _ <- updateOutfitRanks(outfit_id, list) + outfitOpt <- ctx.run(getOutfitById(outfit_id)).map(_.headOption) + memberCount <- ctx.run(query[Outfitmember].filter(_.outfit_id == lift(outfit_id)).size) + pointsTotal <- ctx.run(querySchema[OutfitpointMv]("outfitpoint_mv").filter(_.outfit_id == lift(outfit_id))) + } yield (outfitOpt, memberCount, pointsTotal.headOption.map(_.points).getOrElse(0L)) + + for { + (outfitOpt, memberCount, totalPoints) <- outfitDetails + } yield { + outfitOpt.foreach { outfit => + + // send to all online players in outfit + val outfit_event = OutfitEvent( + outfit_id, + Unk2( + OutfitInfo( + outfit_name = outfit.name, + outfit_points1 = totalPoints, + outfit_points2 = totalPoints, + member_count = memberCount, + outfit_rank_names = OutfitRankNames( + outfit.rank0.getOrElse(""), + outfit.rank1.getOrElse(""), + outfit.rank2.getOrElse(""), + outfit.rank3.getOrElse(""), + outfit.rank4.getOrElse(""), + outfit.rank5.getOrElse(""), + outfit.rank6.getOrElse(""), + outfit.rank7.getOrElse(""), + ), + motd = outfit.motd.getOrElse(""), + unk10 = 0, + unk11 = true, + unk12 = 0, + created_timestamp = outfit.created.atZone(java.time.ZoneOffset.UTC).toInstant.toEpochMilli / 1000, + unk23 = 0, + unk24 = 0, + unk25 = 0 + ) + ) + ) + + zones.foreach(zone => { + zone.AllPlayers.filter(_.outfit_id == outfit_id).foreach(player => { + PlayerControl.sendResponse( + zone, player.Name, + outfit_event + ) + }) + }) + } + } + } + def HandleLoginOutfitCheck(player: Player, session: SessionData): Unit = { ctx.run(getOutfitOnLogin(player.avatar.id)).flatMap { memberships => memberships.headOption match { @@ -729,4 +788,34 @@ object SessionOutfitHandlers { } yield () } } + + def updateOutfitRanksById(outfit_id: Long, list: List[Option[String]]): Quoted[Update[Outfit]] = { + + // Normalize: turn empty strings into None + val normalized = list.map { + case Some(value) if value.trim.nonEmpty => Some(value) + case _ => None + } + + query[Outfit] + .filter(_.id == lift(outfit_id)) + .update( + _.rank0 -> lift(normalized(0)), + _.rank1 -> lift(normalized(1)), + _.rank2 -> lift(normalized(2)), + _.rank3 -> lift(normalized(3)), + _.rank4 -> lift(normalized(4)), + _.rank5 -> lift(normalized(5)), + _.rank6 -> lift(normalized(6)), + _.rank7 -> lift(normalized(7)) + ) + } + + def updateOutfitRanks(outfit_id: Long, list: List[Option[String]]): Future[Unit] = { + ctx.transaction { _ => + for { + _ <- ctx.run(updateOutfitRanksById(outfit_id, list)) + } yield () + } + } }