mirror of
https://github.com/psforever/PSF-LoginServer.git
synced 2026-01-19 18:44:45 +00:00
fix outfit rank names not representing DB values
add MOTD handling renaming OMR packet types with known uses handling outfit promotions (setrank) handle outfit owner changes changing the migration to change to unique index. allows concurrent refresh of MV
This commit is contained in:
parent
ad52c8076c
commit
18dd426d13
|
|
@ -104,4 +104,4 @@ CREATE MATERIALIZED VIEW outfitpoint_mv AS
|
||||||
"outfitpoint"
|
"outfitpoint"
|
||||||
GROUP BY "outfit_id";
|
GROUP BY "outfit_id";
|
||||||
|
|
||||||
CREATE INDEX "outfitpoint_mv_outfit_id_idx" ON "outfitpoint_mv" ("outfit_id");
|
CREATE UNIQUE INDEX "outfitpoint_mv_outfit_id_unique" ON "outfitpoint_mv" ("outfit_id");
|
||||||
|
|
|
||||||
|
|
@ -830,14 +830,13 @@ class GeneralLogic(val ops: GeneralOperations, implicit val context: ActorContex
|
||||||
def handleOutfitRequest(pkt: OutfitRequest): Unit = {
|
def handleOutfitRequest(pkt: OutfitRequest): Unit = {
|
||||||
pkt match {
|
pkt match {
|
||||||
|
|
||||||
|
case OutfitRequest(_, OutfitRequestAction.Motd(message)) =>
|
||||||
|
SessionOutfitHandlers.HandleOutfitMotd(zones, message, player)
|
||||||
|
|
||||||
case OutfitRequest(_, OutfitRequestAction.Ranks(List(r1, r2, r3, r4, r5, r6, r7, r8))) =>
|
case OutfitRequest(_, OutfitRequestAction.Ranks(List(r1, r2, r3, r4, r5, r6, r7, r8))) =>
|
||||||
// update db
|
// 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))))
|
//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))))
|
||||||
|
|
||||||
case OutfitRequest(_, OutfitRequestAction.Motd(message)) =>
|
|
||||||
// update db
|
|
||||||
//sendResponse(OutfitEvent(6418, Unk2(OutfitInfo(player.outfit_name, 0, 0, 1, OutfitRankNames("", "", "", "", "", "", "", ""), message, 0, unk11=true, 0, 8888888, 0, 0, 0))))
|
|
||||||
|
|
||||||
case OutfitRequest(_, OutfitRequestAction.Unk3(true)) =>
|
case OutfitRequest(_, OutfitRequestAction.Unk3(true)) =>
|
||||||
SessionOutfitHandlers.HandleViewOutfitWindow(zones, player, player.outfit_id)
|
SessionOutfitHandlers.HandleViewOutfitWindow(zones, player, player.outfit_id)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
// Copyright (c) 2025 PSForever
|
// Copyright (c) 2025 PSForever
|
||||||
package net.psforever.actors.session.support
|
package net.psforever.actors.session.support
|
||||||
|
|
||||||
import io.getquill.{ActionReturning, EntityQuery, Insert, PostgresJAsyncContext, Query, Quoted, SnakeCase}
|
import io.getquill.{ActionReturning, EntityQuery, Insert, PostgresJAsyncContext, Query, Quoted, SnakeCase, Update}
|
||||||
import net.psforever.objects.avatar.PlayerControl
|
import net.psforever.objects.avatar.PlayerControl
|
||||||
import net.psforever.objects.zones.Zone
|
import net.psforever.objects.zones.Zone
|
||||||
import net.psforever.objects.Player
|
import net.psforever.objects.Player
|
||||||
|
|
@ -19,7 +19,14 @@ import scala.util.{Failure, Success}
|
||||||
object SessionOutfitHandlers {
|
object SessionOutfitHandlers {
|
||||||
|
|
||||||
case class Avatar(id: Long, name: String, faction_id: Int, last_login: java.time.LocalDateTime)
|
case class Avatar(id: Long, name: String, faction_id: Int, last_login: java.time.LocalDateTime)
|
||||||
case class Outfit(id: Long, name: String, faction: Int, owner_id: Long, motd: Option[String], created: java.time.LocalDateTime,
|
case class Outfit(
|
||||||
|
id: Long,
|
||||||
|
name: String,
|
||||||
|
faction: Int,
|
||||||
|
owner_id: Long,
|
||||||
|
motd: Option[String],
|
||||||
|
created: java.time.LocalDateTime,
|
||||||
|
deleted: Boolean,
|
||||||
rank0: Option[String],
|
rank0: Option[String],
|
||||||
rank1: Option[String],
|
rank1: Option[String],
|
||||||
rank2: Option[String],
|
rank2: Option[String],
|
||||||
|
|
@ -27,7 +34,8 @@ object SessionOutfitHandlers {
|
||||||
rank4: Option[String],
|
rank4: Option[String],
|
||||||
rank5: Option[String],
|
rank5: Option[String],
|
||||||
rank6: Option[String],
|
rank6: Option[String],
|
||||||
rank7: Option[String])
|
rank7: Option[String]
|
||||||
|
)
|
||||||
case class Outfitmember(id: Long, outfit_id: Long, avatar_id: Long, rank: Int)
|
case class Outfitmember(id: Long, outfit_id: Long, avatar_id: Long, rank: Int)
|
||||||
case class Outfitpoint(id: Long, outfit_id: Long, avatar_id: Option[Long], points: Long)
|
case class Outfitpoint(id: Long, outfit_id: Long, avatar_id: Option[Long], points: Long)
|
||||||
case class OutfitpointMv(outfit_id: Long, points: Long)
|
case class OutfitpointMv(outfit_id: Long, points: Long)
|
||||||
|
|
@ -126,12 +134,12 @@ object SessionOutfitHandlers {
|
||||||
|
|
||||||
PlayerControl.sendResponse(outfitInvite.sentFrom.Zone, outfitInvite.sentFrom.Name,
|
PlayerControl.sendResponse(outfitInvite.sentFrom.Zone, outfitInvite.sentFrom.Name,
|
||||||
OutfitMembershipResponse(
|
OutfitMembershipResponse(
|
||||||
OutfitMembershipResponse.PacketType.Unk2, 0, 0,
|
OutfitMembershipResponse.PacketType.InviteAccepted, 0, 0,
|
||||||
invited.CharId, outfitInvite.sentFrom.CharId, invited.Name, outfit.name, flag = false))
|
invited.CharId, outfitInvite.sentFrom.CharId, invited.Name, outfit.name, flag = false))
|
||||||
|
|
||||||
PlayerControl.sendResponse(invited.Zone, invited.Name,
|
PlayerControl.sendResponse(invited.Zone, invited.Name,
|
||||||
OutfitMembershipResponse(
|
OutfitMembershipResponse(
|
||||||
OutfitMembershipResponse.PacketType.Unk2, 0, 0,
|
OutfitMembershipResponse.PacketType.InviteAccepted, 0, 0,
|
||||||
invited.CharId, outfitInvite.sentFrom.CharId, invited.Name, outfit.name, flag = true))
|
invited.CharId, outfitInvite.sentFrom.CharId, invited.Name, outfit.name, flag = true))
|
||||||
|
|
||||||
PlayerControl.sendResponse(outfitInvite.sentFrom.Zone, outfitInvite.sentFrom.Name,
|
PlayerControl.sendResponse(outfitInvite.sentFrom.Zone, outfitInvite.sentFrom.Name,
|
||||||
|
|
@ -183,12 +191,12 @@ object SessionOutfitHandlers {
|
||||||
|
|
||||||
PlayerControl.sendResponse(outfitInvite.sentFrom.Zone, outfitInvite.sentFrom.Name,
|
PlayerControl.sendResponse(outfitInvite.sentFrom.Zone, outfitInvite.sentFrom.Name,
|
||||||
OutfitMembershipResponse(
|
OutfitMembershipResponse(
|
||||||
OutfitMembershipResponse.PacketType.Unk3, 0, 0,
|
OutfitMembershipResponse.PacketType.InviteRejected, 0, 0,
|
||||||
invited.CharId, outfitInvite.sentFrom.CharId, invited.Name, "", flag = false))
|
invited.CharId, outfitInvite.sentFrom.CharId, invited.Name, "", flag = false))
|
||||||
|
|
||||||
PlayerControl.sendResponse(invited.Zone, invited.Name,
|
PlayerControl.sendResponse(invited.Zone, invited.Name,
|
||||||
OutfitMembershipResponse(
|
OutfitMembershipResponse(
|
||||||
OutfitMembershipResponse.PacketType.Unk3, 0, 0,
|
OutfitMembershipResponse.PacketType.InviteRejected, 0, 0,
|
||||||
invited.CharId, outfitInvite.sentFrom.CharId, invited.Name, "", flag = true))
|
invited.CharId, outfitInvite.sentFrom.CharId, invited.Name, "", flag = true))
|
||||||
|
|
||||||
OutfitInviteManager.removeOutfitInvite(invited.CharId)
|
OutfitInviteManager.removeOutfitInvite(invited.CharId)
|
||||||
|
|
@ -277,10 +285,60 @@ object SessionOutfitHandlers {
|
||||||
}
|
}
|
||||||
|
|
||||||
def HandleOutfitPromote(zones: Seq[Zone], promotedId: Long, newRank: Int, promoter: Player): Unit = {
|
def HandleOutfitPromote(zones: Seq[Zone], promotedId: Long, newRank: Int, promoter: Player): Unit = {
|
||||||
// send to all online players in outfit
|
|
||||||
|
val outfit_id = promoter.outfit_id
|
||||||
|
|
||||||
findPlayerByIdForOutfitAction(zones, promotedId, promoter).foreach { promoted =>
|
findPlayerByIdForOutfitAction(zones, promotedId, promoter).foreach { promoted =>
|
||||||
PlayerControl.sendResponse(promoted.Zone, promoted.Name, OutfitMemberEvent(6418, promotedId, OutfitMemberEventAction.Unk0(promoted.Name, newRank, 1032432, 0, OutfitMemberEventAction.PacketType.Padding, 0)))
|
|
||||||
PlayerControl.sendResponse(promoter.Zone, promoter.Name, OutfitMemberEvent(6418, promotedId, OutfitMemberEventAction.Unk0(promoted.Name, newRank, 1032432, 0, OutfitMemberEventAction.PacketType.Padding, 0)))
|
if (newRank == 7) {
|
||||||
|
|
||||||
|
// demote owner to rank 6
|
||||||
|
// promote promoted to rank 7
|
||||||
|
// update outfit
|
||||||
|
updateOutfitOwner(outfit_id, promoter.avatar.id, promoted.avatar.id)
|
||||||
|
|
||||||
|
// TODO: does every member get the notification like this?
|
||||||
|
getOutfitMemberPoints(outfit_id, promoter.avatar.id).map {
|
||||||
|
owner_points =>
|
||||||
|
// announce owner rank change
|
||||||
|
zones.foreach(zone => {
|
||||||
|
zone.AllPlayers.filter(_.outfit_id == outfit_id).foreach(outfitMember => {
|
||||||
|
PlayerControl.sendResponse(
|
||||||
|
zone, outfitMember.Name,
|
||||||
|
OutfitMemberEvent(outfit_id, promoter.avatar.id,
|
||||||
|
OutfitMemberEventAction.Unk0(promoter.Name, 6, owner_points, 0, OutfitMemberEventAction.PacketType.Padding, 0)))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// update promoter rank
|
||||||
|
PlayerControl.sendResponse(
|
||||||
|
promoter.Zone, promoter.Name,
|
||||||
|
OutfitMemberUpdate(outfit_id, promoter.avatar.id, rank = 6, flag = true))
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// promote promoted
|
||||||
|
updateOutfitMemberRank(outfit_id, promoted.avatar.id, rank = newRank)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: does every member get the notification like this?
|
||||||
|
getOutfitMemberPoints(outfit_id, promoted.avatar.id).map {
|
||||||
|
member_points =>
|
||||||
|
// tell everyone about the new rank of the promoted member
|
||||||
|
zones.foreach(zone => {
|
||||||
|
zone.AllPlayers.filter(_.outfit_id == outfit_id).foreach(player => {
|
||||||
|
PlayerControl.sendResponse(
|
||||||
|
zone, player.Name,
|
||||||
|
OutfitMemberEvent(outfit_id, promoted.avatar.id,
|
||||||
|
OutfitMemberEventAction.Unk0(promoted.Name, newRank, member_points, 0, OutfitMemberEventAction.PacketType.Padding, 0)))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// update promoted rank
|
||||||
|
PlayerControl.sendResponse(
|
||||||
|
promoted.Zone, promoted.Name,
|
||||||
|
OutfitMemberUpdate(outfit_id, promoted.avatar.id, rank = newRank, flag = true))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -306,7 +364,16 @@ object SessionOutfitHandlers {
|
||||||
totalPoints,
|
totalPoints,
|
||||||
totalPoints,
|
totalPoints,
|
||||||
memberCount,
|
memberCount,
|
||||||
OutfitRankNames("", "", "", "", "", "", "", ""),
|
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(""),
|
||||||
|
),
|
||||||
outfit.motd.getOrElse(""),
|
outfit.motd.getOrElse(""),
|
||||||
14, unk11 = true, 0, seconds, 0, 0, 0))))
|
14, unk11 = true, 0, seconds, 0, 0, 0))))
|
||||||
|
|
||||||
|
|
@ -355,6 +422,71 @@ object SessionOutfitHandlers {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def HandleOutfitMotd(zones: Seq[Zone], message: String, player: Player): Unit = {
|
||||||
|
|
||||||
|
val outfit_id = player.outfit_id
|
||||||
|
|
||||||
|
// update MOTD
|
||||||
|
updateOutfitMotd(outfit_id, message)
|
||||||
|
|
||||||
|
// TODO this does not notify clients with open windows. Do they update in the first place?
|
||||||
|
val outfitDetails = for {
|
||||||
|
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
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// C >> S OutfitRequest(41593365, Motd(Vanu outfit for the planetside forever project! -find out more about the PSEMU project at PSforever.net))
|
||||||
|
// 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)))
|
||||||
|
}
|
||||||
|
|
||||||
/* supporting functions */
|
/* supporting functions */
|
||||||
|
|
||||||
def sanitizeOutfitName(name: String): Option[String] = {
|
def sanitizeOutfitName(name: String): Option[String] = {
|
||||||
|
|
@ -435,12 +567,14 @@ object SessionOutfitHandlers {
|
||||||
for {
|
for {
|
||||||
deleted <- ctx.run(
|
deleted <- ctx.run(
|
||||||
query[Outfitmember]
|
query[Outfitmember]
|
||||||
.filter(m => m.outfit_id == lift(outfit_id) && m.avatar_id == lift(avatar_id))
|
.filter(_.outfit_id == lift(outfit_id))
|
||||||
|
.filter(_.avatar_id == lift(avatar_id))
|
||||||
.delete
|
.delete
|
||||||
)
|
)
|
||||||
updated <- ctx.run(
|
updated <- ctx.run(
|
||||||
query[Outfitpoint]
|
query[Outfitpoint]
|
||||||
.filter(p => p.outfit_id == lift(outfit_id) && p.avatar_id == lift(avatarOpt))
|
.filter(_.outfit_id == lift(outfit_id))
|
||||||
|
.filter(_.avatar_id == lift(avatarOpt))
|
||||||
.update(_.avatar_id -> None)
|
.update(_.avatar_id -> None)
|
||||||
)
|
)
|
||||||
} yield (deleted, updated)
|
} yield (deleted, updated)
|
||||||
|
|
@ -455,6 +589,18 @@ object SessionOutfitHandlers {
|
||||||
query[Outfitmember].filter(_.outfit_id == lift(id)).size
|
query[Outfitmember].filter(_.outfit_id == lift(id)).size
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def getOutfitMemberPoints(outfit_id: Long, avatar_id: Long): Future[Long] = {
|
||||||
|
val avatarOpt: Option[Long] = Some(avatar_id)
|
||||||
|
for {
|
||||||
|
points <- ctx.run(
|
||||||
|
query[Outfitpoint]
|
||||||
|
.filter(_.outfit_id == lift(outfit_id))
|
||||||
|
.filter(_.avatar_id == lift(avatarOpt))
|
||||||
|
.map(_.points)
|
||||||
|
)
|
||||||
|
} yield (points.headOption.getOrElse(0))
|
||||||
|
}
|
||||||
|
|
||||||
def getOutfitPoints(id: Long): Quoted[EntityQuery[OutfitpointMv]] = quote {
|
def getOutfitPoints(id: Long): Quoted[EntityQuery[OutfitpointMv]] = quote {
|
||||||
querySchema[OutfitpointMv]("outfitpoint_mv").filter(_.outfit_id == lift(id))
|
querySchema[OutfitpointMv]("outfitpoint_mv").filter(_.outfit_id == lift(id))
|
||||||
}
|
}
|
||||||
|
|
@ -490,4 +636,49 @@ object SessionOutfitHandlers {
|
||||||
(outfit.id, points.map(_.points).getOrElse(0L), outfit.name, leader.name, memberCounts.map(_._2).getOrElse(0L))
|
(outfit.id, points.map(_.points).getOrElse(0L), outfit.name, leader.name, memberCounts.map(_._2).getOrElse(0L))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def updateMemberRankById(outfit_id: Long, avatar_id: Long, rank: Int): Quoted[Update[Outfitmember]] = quote {
|
||||||
|
query[Outfitmember]
|
||||||
|
.filter(_.outfit_id == lift(outfit_id))
|
||||||
|
.filter(_.avatar_id == lift(avatar_id))
|
||||||
|
.update(_.rank -> lift(rank))
|
||||||
|
}
|
||||||
|
|
||||||
|
def updateOutfitMemberRank(outfit_id: Long, avatar_id: Long, rank: Int): Future[Unit] = {
|
||||||
|
ctx.transaction { implicit ec =>
|
||||||
|
for {
|
||||||
|
_ <- ctx.run(updateMemberRankById(outfit_id, avatar_id, rank))
|
||||||
|
} yield ()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def updateOutfitOwnerById(outfit_id: Long, owner_id: Long): Quoted[Update[Outfit]] = quote {
|
||||||
|
query[Outfit]
|
||||||
|
.filter(_.id == lift(outfit_id))
|
||||||
|
.update(_.owner_id -> lift(owner_id))
|
||||||
|
}
|
||||||
|
|
||||||
|
def updateOutfitOwner(outfit_id: Long, owner_id: Long, new_owner_id: Long): Future[Unit] = {
|
||||||
|
ctx.transaction { implicit ec =>
|
||||||
|
for {
|
||||||
|
_ <- ctx.run(updateMemberRankById(outfit_id, owner_id, 6))
|
||||||
|
_ <- ctx.run(updateMemberRankById(outfit_id, new_owner_id, 7))
|
||||||
|
_ <- ctx.run(updateOutfitOwnerById(outfit_id, new_owner_id))
|
||||||
|
} yield ()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def updateOutfitMotdById(outfit_id: Long, motd: Option[String]): Quoted[Update[Outfit]] = quote {
|
||||||
|
query[Outfit]
|
||||||
|
.filter(_.id == lift(outfit_id))
|
||||||
|
.update(_.motd -> lift(motd))
|
||||||
|
}
|
||||||
|
|
||||||
|
def updateOutfitMotd(outfit_id: Long, motd: String): Future[Unit] = {
|
||||||
|
ctx.transaction { implicit ec =>
|
||||||
|
for {
|
||||||
|
_ <- ctx.run(updateOutfitMotdById(outfit_id, Some(motd)))
|
||||||
|
} yield ()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -31,9 +31,9 @@ object OutfitMembershipResponse extends Marshallable[OutfitMembershipResponse] {
|
||||||
type Type = Value
|
type Type = Value
|
||||||
|
|
||||||
val CreateResponse: PacketType.Value = Value(0)
|
val CreateResponse: PacketType.Value = Value(0)
|
||||||
val Invite: PacketType.Value = Value(1) // Info: Player has been invited / response to OutfitMembershipRequest Unk2 for that player
|
val Invite: PacketType.Value = Value(1) // response to OutfitMembershipRequest Unk2 for that player
|
||||||
val Unk2: PacketType.Value = Value(2) // Invited / Accepted / Added
|
val InviteAccepted: PacketType.Value = Value(2)
|
||||||
val Unk3: PacketType.Value = Value(3)
|
val InviteRejected: PacketType.Value = Value(3)
|
||||||
val Unk4: PacketType.Value = Value(4)
|
val Unk4: PacketType.Value = Value(4)
|
||||||
val Kick: PacketType.Value = Value(5)
|
val Kick: PacketType.Value = Value(5)
|
||||||
val Unk6: PacketType.Value = Value(6) // 6 and 7 seen as failed decodes, validity unknown
|
val Unk6: PacketType.Value = Value(6) // 6 and 7 seen as failed decodes, validity unknown
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ import scodec.codecs._
|
||||||
import shapeless.{::, HNil}
|
import shapeless.{::, HNil}
|
||||||
|
|
||||||
final case class OutfitRequest(
|
final case class OutfitRequest(
|
||||||
id: Long,
|
outfit_id: Long,
|
||||||
action: OutfitRequestAction
|
action: OutfitRequestAction
|
||||||
) extends PlanetSideGamePacket {
|
) extends PlanetSideGamePacket {
|
||||||
type Packet = OutfitRequest
|
type Packet = OutfitRequest
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,7 @@ class OutfitMembershipResponseTest extends Specification {
|
||||||
"decode unk1" in {
|
"decode unk1" in {
|
||||||
PacketCoding.decodePacket(unk1).require match {
|
PacketCoding.decodePacket(unk1).require match {
|
||||||
case OutfitMembershipResponse(packet_type, unk0, unk1, outfit_id, target_id, str1, str2, flag) =>
|
case OutfitMembershipResponse(packet_type, unk0, unk1, outfit_id, target_id, str1, str2, flag) =>
|
||||||
packet_type mustEqual PacketType.Unk1
|
packet_type mustEqual PacketType.Invite
|
||||||
unk0 mustEqual 0
|
unk0 mustEqual 0
|
||||||
unk1 mustEqual 0
|
unk1 mustEqual 0
|
||||||
outfit_id mustEqual 30383325
|
outfit_id mustEqual 30383325
|
||||||
|
|
@ -56,7 +56,7 @@ class OutfitMembershipResponseTest extends Specification {
|
||||||
}
|
}
|
||||||
|
|
||||||
"encode unk1" in {
|
"encode unk1" in {
|
||||||
val msg = OutfitMembershipResponse(PacketType.Unk1, 0, 0, 30383325, 41605870, "xNick", "PlanetSide_Forever_TR", flag = false)
|
val msg = OutfitMembershipResponse(PacketType.Invite, 0, 0, 30383325, 41605870, "xNick", "PlanetSide_Forever_TR", flag = false)
|
||||||
val pkt = PacketCoding.encodePacket(msg).require.toByteVector
|
val pkt = PacketCoding.encodePacket(msg).require.toByteVector
|
||||||
|
|
||||||
pkt mustEqual unk1
|
pkt mustEqual unk1
|
||||||
|
|
@ -65,7 +65,7 @@ class OutfitMembershipResponseTest extends Specification {
|
||||||
"decode unk2" in {
|
"decode unk2" in {
|
||||||
PacketCoding.decodePacket(unk2).require match {
|
PacketCoding.decodePacket(unk2).require match {
|
||||||
case OutfitMembershipResponse(packet_type, unk0, unk1, outfit_id, target_id, str1, str2, flag) =>
|
case OutfitMembershipResponse(packet_type, unk0, unk1, outfit_id, target_id, str1, str2, flag) =>
|
||||||
packet_type mustEqual PacketType.Unk2
|
packet_type mustEqual PacketType.InviteAccepted
|
||||||
unk0 mustEqual 0
|
unk0 mustEqual 0
|
||||||
unk1 mustEqual 0
|
unk1 mustEqual 0
|
||||||
outfit_id mustEqual 41605156
|
outfit_id mustEqual 41605156
|
||||||
|
|
@ -79,7 +79,7 @@ class OutfitMembershipResponseTest extends Specification {
|
||||||
}
|
}
|
||||||
|
|
||||||
"encode unk2" in {
|
"encode unk2" in {
|
||||||
val msg = OutfitMembershipResponse(PacketType.Unk2, 0, 0, 41605156, 41593365, "Zergling92", "PlanetSide_Forever_Vanu", flag = false)
|
val msg = OutfitMembershipResponse(PacketType.InviteAccepted, 0, 0, 41605156, 41593365, "Zergling92", "PlanetSide_Forever_Vanu", flag = false)
|
||||||
val pkt = PacketCoding.encodePacket(msg).require.toByteVector
|
val pkt = PacketCoding.encodePacket(msg).require.toByteVector
|
||||||
|
|
||||||
pkt mustEqual unk2
|
pkt mustEqual unk2
|
||||||
|
|
@ -88,7 +88,7 @@ class OutfitMembershipResponseTest extends Specification {
|
||||||
"decode unk3" in {
|
"decode unk3" in {
|
||||||
PacketCoding.decodePacket(unk3).require match {
|
PacketCoding.decodePacket(unk3).require match {
|
||||||
case OutfitMembershipResponse(packet_type, unk0, unk1, outfit_id, target_id, str1, str2, flag) =>
|
case OutfitMembershipResponse(packet_type, unk0, unk1, outfit_id, target_id, str1, str2, flag) =>
|
||||||
packet_type mustEqual PacketType.Unk3
|
packet_type mustEqual PacketType.InviteRejected
|
||||||
unk0 mustEqual 0
|
unk0 mustEqual 0
|
||||||
unk1 mustEqual 0
|
unk1 mustEqual 0
|
||||||
outfit_id mustEqual 41574772
|
outfit_id mustEqual 41574772
|
||||||
|
|
@ -102,7 +102,7 @@ class OutfitMembershipResponseTest extends Specification {
|
||||||
}
|
}
|
||||||
|
|
||||||
"encode unk3" in {
|
"encode unk3" in {
|
||||||
val msg = OutfitMembershipResponse(PacketType.Unk3, 0, 0, 41574772, 31156616, "", "", flag = true)
|
val msg = OutfitMembershipResponse(PacketType.InviteRejected, 0, 0, 41574772, 31156616, "", "", flag = true)
|
||||||
val pkt = PacketCoding.encodePacket(msg).require.toByteVector
|
val pkt = PacketCoding.encodePacket(msg).require.toByteVector
|
||||||
|
|
||||||
pkt mustEqual unk3
|
pkt mustEqual unk3
|
||||||
|
|
@ -134,7 +134,7 @@ class OutfitMembershipResponseTest extends Specification {
|
||||||
"decode unk5" in {
|
"decode unk5" in {
|
||||||
PacketCoding.decodePacket(unk5).require match {
|
PacketCoding.decodePacket(unk5).require match {
|
||||||
case OutfitMembershipResponse(packet_type, unk0, unk1, outfit_id, target_id, str1, str2, flag) =>
|
case OutfitMembershipResponse(packet_type, unk0, unk1, outfit_id, target_id, str1, str2, flag) =>
|
||||||
packet_type mustEqual PacketType.Unk5
|
packet_type mustEqual PacketType.Kick
|
||||||
unk0 mustEqual 0
|
unk0 mustEqual 0
|
||||||
unk1 mustEqual 1
|
unk1 mustEqual 1
|
||||||
outfit_id mustEqual 41593365
|
outfit_id mustEqual 41593365
|
||||||
|
|
@ -148,7 +148,7 @@ class OutfitMembershipResponseTest extends Specification {
|
||||||
}
|
}
|
||||||
|
|
||||||
"encode unk5" in {
|
"encode unk5" in {
|
||||||
val msg = OutfitMembershipResponse(PacketType.Unk5, 0, 1, 41593365, 41605263, "PSFoutfittest1", "", flag = true)
|
val msg = OutfitMembershipResponse(PacketType.Kick, 0, 1, 41593365, 41605263, "PSFoutfittest1", "", flag = true)
|
||||||
val pkt = PacketCoding.encodePacket(msg).require.toByteVector
|
val pkt = PacketCoding.encodePacket(msg).require.toByteVector
|
||||||
|
|
||||||
pkt mustEqual unk5
|
pkt mustEqual unk5
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue