More fixes

* Fix !list not distinguishing between players and corpses
* Fix /worldkick not working
* /silence no longer responds with a message window
* Fix 96-99 zone map files
* Fix implants not resetting after being jammend
* Fix MAXes requiring the wrong certs
This commit is contained in:
Jakob Gillich 2020-08-27 23:04:05 +02:00
parent 8a0a7d8539
commit 08eed0f331
11 changed files with 28599 additions and 28587 deletions

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -168,7 +168,7 @@ object AvatarActor {
final case class DeactivateActiveImplants() extends Command
/** Start implant initialization timers (after zoning or respawn) */
final case class InitializeImplants(instant: Boolean = false) extends Command
final case class InitializeImplants() extends Command
/** Deinitialize implants (before zoning or respawning) */
final case class DeinitializeImplants() extends Command
@ -582,6 +582,7 @@ class AvatarActor(
)
case _ => ;
}
deinitializeImplants()
Behaviors.same
case LearnImplant(terminalGuid, definition) =>
@ -880,8 +881,8 @@ class AvatarActor(
)
Behaviors.same
case InitializeImplants(instant) =>
initializeImplants(instant)
case InitializeImplants() =>
initializeImplants()
Behaviors.same
case DeinitializeImplants() =>
@ -890,7 +891,7 @@ class AvatarActor(
case ResetImplants() =>
deinitializeImplants()
initializeImplants(instant = false)
initializeImplants()
Behaviors.same
case AwardBep(bep) =>
@ -1026,7 +1027,7 @@ class AvatarActor(
consumed
}
def initializeImplants(instant: Boolean): Unit = {
def initializeImplants(): Unit = {
avatar.implants.zipWithIndex.foreach {
case (Some(implant), slot) =>
// TODO if this implant is Installed but does not have shortcut, add to a free slot or write over slot 61/62/63
@ -1051,7 +1052,7 @@ class AvatarActor(
implantTimers.get(slot).foreach(_.cancel())
implantTimers(slot) = context.system.scheduler.scheduleOnce(
if (instant) 0.seconds else implant.definition.InitializationDuration.seconds,
implant.definition.InitializationDuration.seconds,
() => {
avatar = avatar.copy(implants = avatar.implants.map {
case Some(implant) => Some(implant.copy(initialized = true))
@ -1071,9 +1072,8 @@ class AvatarActor(
avatar = avatar.copy(implants = avatar.implants.zipWithIndex.map {
case (Some(implant), slot) =>
if (implant.active) {
context.self ! DeactivateImplant(implant.definition.implantType)
deactivateImplant(implant.definition.implantType)
}
sessionActor ! SessionActor.SendResponse(ActionProgressMessage(slot + 6, 100))
session.get.zone.AvatarEvents ! AvatarServiceMessage(
session.get.zone.id,
AvatarAction.SendResponse(

View file

@ -318,14 +318,15 @@ class ChatActor(
(zone.LivePlayers ++ zone.Corpses)
.filter(_.CharId != session.player.CharId)
.sortBy(_.Name)
.sortBy(p => (p.Name, !p.isAlive))
.foreach(player => {
val color = if (!player.isAlive) "\\#7" else ""
sessionActor ! SessionActor.SendResponse(
ChatMsg(
CMT_GMOPEN,
message.wideContents,
"Server",
s"\\#7${player.Name} (${player.Faction}) [${player.CharId}] at ${player.Position.x.toInt} ${player.Position.y.toInt} ${player.Position.z.toInt}",
s"${color}${player.Name} (${player.Faction}) [${player.CharId}] at ${player.Position.x.toInt} ${player.Position.y.toInt} ${player.Position.z.toInt}",
message.note
)
)
@ -824,45 +825,54 @@ class ChatActor(
}
case (CMT_KICK, _, contents) if gmCommandAllowed =>
val input = contents.split("\\s+").drop(1)
if (input.length > 0) {
val numRegex = raw"(\d+)".r
val id = input(0)
val determination: Player => Boolean = id match {
case numRegex(_) => _.CharId == id.toLong
case _ => _.Name.equals(id)
}
session.zone.LivePlayers
.find(determination)
.orElse(session.zone.Corpses.find(determination)) match {
case Some(player) =>
input.lift(1) match {
case Some(numRegex(time)) =>
sessionActor ! SessionActor.Kick(player, Some(time.toLong))
case _ =>
sessionActor ! SessionActor.Kick(player)
}
val inputs = contents.split("\\s+").filter(_ != "")
inputs.headOption match {
case Some(input) =>
val determination: Player => Boolean = input.toLongOption match {
case Some(id) => _.CharId == id
case _ => _.Name.equals(input)
}
session.zone.LivePlayers
.find(determination)
.orElse(session.zone.Corpses.find(determination)) match {
case Some(player) =>
inputs.lift(1).map(_.toLongOption) match {
case Some(Some(time)) =>
sessionActor ! SessionActor.Kick(player, Some(time))
case _ =>
sessionActor ! SessionActor.Kick(player)
}
sessionActor ! SessionActor.SendResponse(
ChatMsg(
CMT_GMOPEN,
message.wideContents,
"Server",
"@kick_o",
message.note
sessionActor ! SessionActor.SendResponse(
ChatMsg(
UNK_229,
message.wideContents,
"Server",
"@kick_i",
message.note
)
)
)
case None =>
sessionActor ! SessionActor.SendResponse(
ChatMsg(
CMT_GMOPEN,
message.wideContents,
"Server",
"@kick_o",
message.note
case None =>
sessionActor ! SessionActor.SendResponse(
ChatMsg(
UNK_229,
message.wideContents,
"Server",
"@kick_o",
message.note
)
)
}
case None =>
sessionActor ! SessionActor.SendResponse(
ChatMsg(
UNK_229,
message.wideContents,
"Server",
"@kick_o",
message.note
)
}
)
}
case _ =>
@ -874,7 +884,7 @@ class ChatActor(
message.messageType match {
case CMT_TELL | U_CMT_TELLFROM | CMT_BROADCAST | CMT_SQUAD | CMT_PLATOON | CMT_COMMAND | UNK_45 | UNK_71 |
CMT_NOTE | CMT_GMBROADCAST | CMT_GMBROADCAST_NC | CMT_GMBROADCAST_TR | CMT_GMBROADCAST_VS |
CMT_GMBROADCASTPOPUP | CMT_GMTELL | U_CMT_GMTELLFROM | UNK_227 =>
CMT_GMBROADCASTPOPUP | CMT_GMTELL | U_CMT_GMTELLFROM | UNK_227 | UNK_229 =>
sessionActor ! SessionActor.SendResponse(message)
case CMT_OPEN =>
if (
@ -906,20 +916,20 @@ class ChatActor(
if (session.player.silenced) {
sessionActor ! SessionActor.SetSilenced(false)
sessionActor ! SessionActor.SendResponse(
ChatMsg(ChatMessageType.UNK_71, true, "", "@silence_off", None)
ChatMsg(ChatMessageType.UNK_229, true, "", "@silence_off", None)
)
if (!silenceTimer.isCancelled) silenceTimer.cancel()
} else {
sessionActor ! SessionActor.SetSilenced(true)
sessionActor ! SessionActor.SendResponse(
ChatMsg(ChatMessageType.UNK_71, true, "", "@silence_on", None)
ChatMsg(ChatMessageType.UNK_229, true, "", "@silence_on", None)
)
silenceTimer = context.system.scheduler.scheduleOnce(
time minutes,
() => {
sessionActor ! SessionActor.SetSilenced(false)
sessionActor ! SessionActor.SendResponse(
ChatMsg(ChatMessageType.UNK_71, true, "", "@silence_timeout", None)
ChatMsg(ChatMessageType.UNK_229, true, "", "@silence_timeout", None)
)
}
)

View file

@ -1284,6 +1284,8 @@ class SessionActor extends Actor with MDCContextAware {
log.info(s"Player ${tplayer.Name} has been loaded")
tplayer.avatar = avatar
session = session.copy(player = tplayer)
avatarActor ! AvatarActor.CreateImplants()
avatarActor ! AvatarActor.InitializeImplants()
//LoadMapMessage causes the client to send BeginZoningMessage, eventually leading to SetCurrentAvatar
val weaponsEnabled =
session.zone.map.name != "map11" && session.zone.map.name != "map12" && session.zone.map.name != "map13"
@ -1309,8 +1311,6 @@ class SessionActor extends Actor with MDCContextAware {
keepAliveFunc = NormalKeepAlive
upstreamMessageCount = 0
setAvatar = false
avatarActor ! AvatarActor.CreateImplants()
avatarActor ! AvatarActor.InitializeImplants()
persist()
case PlayerLoaded(tplayer) =>
@ -1337,24 +1337,24 @@ class SessionActor extends Actor with MDCContextAware {
failWithError(s"${tplayer.Name} failed to load anywhere")
}
/*
The user is either already in the current zone and merely transporting himself from one location to another,
also called "dying", or occasionally "deconstructing,"
or is completely switching in between zones.
These correspond to the message NewPlayerLoaded for the case of "dying" or the latter zone switching case,
and PlayerLoaded for "deconstruction."
In the latter case, the user must wait for the zone to be recognized as loaded for the server
and this is performed through the send LoadMapMessage, receive BeginZoningMessage exchange
The user's player should have already been registered into the new zone
and is at some stage of being added to the zone in which they will have control agency in that zone.
Whether or not the zone is loaded in the earlier case depends on the destination with respect to the current location.
Once all of the following is (assumed) accomplished,
the server will attempt to declare that user's player the avatar of the user's client.
Reception of certain packets that represent "reported user activity" after that marks the end of avatar loading.
If the maximum number of unsuccessful attempts is reached, some course of action is taken.
If the player dies, the process does not need to continue.
He may or may not be accompanied by a vehicle at any stage of this process.
*/
/**
* The user is either already in the current zone and merely transporting himself from one location to another,
* also called "dying", or occasionally "deconstructing,"
* or is completely switching in between zones.
* These correspond to the message NewPlayerLoaded for the case of "dying" or the latter zone switching case,
* and PlayerLoaded for "deconstruction."
* In the latter case, the user must wait for the zone to be recognized as loaded for the server
* and this is performed through the send LoadMapMessage, receive BeginZoningMessage exchange
* The user's player should have already been registered into the new zone
* and is at some stage of being added to the zone in which they will have control agency in that zone.
* Whether or not the zone is loaded in the earlier case depends on the destination with respect to the current location.
* Once all of the following is (assumed) accomplished,
* the server will attempt to declare that user's player the avatar of the user's client.
* Reception of certain packets that represent "reported user activity" after that marks the end of avatar loading.
* If the maximum number of unsuccessful attempts is reached, some course of action is taken.
* If the player dies, the process does not need to continue.
* He may or may not be accompanied by a vehicle at any stage of this process.
*/
case SetCurrentAvatar(tplayer, max_attempts, attempt) =>
respawnTimer.cancel()
val waitingOnUpstream = upstreamMessageCount == 0
@ -3064,6 +3064,7 @@ class SessionActor extends Actor with MDCContextAware {
player.Actor ! JammableUnit.ClearJammeredStatus()
player.Actor ! JammableUnit.ClearJammeredSound()
}
// TODO only when respawning after death
avatarActor ! AvatarActor.ResetImplants()
sendResponse(PlanetsideAttributeMessage(PlanetSideGUID(0), 82, 0))
@ -4507,7 +4508,8 @@ class SessionActor extends Actor with MDCContextAware {
} else {
avatarActor ! AvatarActor.DeactivateImplant(implant.definition.implantType)
}
case _ => log.error(s"AvatarImplantMessage for unknown or uninitialized implant ${msg}")
case Some(implant) if !implant.initialized => ()
case _ => log.error(s"AvatarImplantMessage for unknown implant ${msg}")
}
}
@ -5683,7 +5685,7 @@ class SessionActor extends Actor with MDCContextAware {
log.info("Battleplan: " + msg)
case msg @ CreateShortcutMessage(player_guid, slot, unk, add, shortcut) =>
log.info("CreateShortcutMessage: " + msg)
log.debug("CreateShortcutMessage: " + msg)
case msg @ FriendsRequest(action, friend) =>
log.info("FriendsRequest: " + msg)
@ -7116,10 +7118,10 @@ class SessionActor extends Actor with MDCContextAware {
*/
def RespawnClone(tplayer: Player): Player = {
// workaround to make sure player is spawned with full stamina
tplayer.avatar = tplayer.avatar.copy(stamina = avatar.maxStamina)
val obj = Player.Respawn(tplayer)
player.avatar = player.avatar.copy(stamina = avatar.maxStamina)
avatarActor ! AvatarActor.RestoreStamina(avatar.maxStamina)
avatarActor ! AvatarActor.ResetImplants()
val obj = Player.Respawn(tplayer)
DefinitionUtil.applyDefaultLoadout(obj)
obj.death_by = tplayer.death_by
obj
@ -8320,7 +8322,7 @@ class SessionActor extends Actor with MDCContextAware {
respawnTime.toMillis,
Vector3.Zero,
player.Faction,
true
unk5 = true
)
)
shiftPosition = Some(pos)

View file

@ -726,7 +726,7 @@ class PlayerControl(player: Player, avatarActor: typed.ActorRef[AvatarActor.Comm
}
override def CancelJammeredStatus(target: Any): Unit = {
avatarActor ! AvatarActor.InitializeImplants(instant = true)
avatarActor ! AvatarActor.InitializeImplants()
super.CancelJammeredStatus(target)
}

View file

@ -115,9 +115,9 @@ object InfantryLoadout {
*/
def DetermineSubtypeC(subtype: Int): Set[Certification] =
subtype match {
case 1 => Set(Certification.AIMAX, Certification.UniMAX)
case 2 => Set(Certification.AVMAX, Certification.UniMAX)
case 3 => Set(Certification.AAMAX, Certification.UniMAX)
case 1 => Set(Certification.AAMAX, Certification.UniMAX)
case 2 => Set(Certification.AIMAX, Certification.UniMAX)
case 3 => Set(Certification.AVMAX, Certification.UniMAX)
case _ => Set.empty[Certification]
}
}

View file

@ -164,30 +164,30 @@ case object MapInfo extends StringEnum[MapInfo] {
scale = MapScale.Dim2560
)
case object Map99
case object Map96
extends MapInfo(
value = "map99",
value = "map96",
checksum = 846603446L,
scale = MapScale.Dim4096
)
case object Map98
extends MapInfo(
value = "map98",
checksum = 2810790213L,
scale = MapScale.Dim4096
)
case object Map97
extends MapInfo(
value = "map97",
checksum = 2810790213L,
scale = MapScale.Dim4096
)
case object Map98
extends MapInfo(
value = "map98",
checksum = 3654267088L,
scale = MapScale.Dim4096
)
case object Map96
case object Map99
extends MapInfo(
value = "map96",
value = "map99",
checksum = 4113726460L,
scale = MapScale.Dim4096
)

View file

@ -116,13 +116,13 @@ class ChatService(context: ActorContext[ChatService.Command]) extends AbstractBe
if (recipient.session.player.silenced) {
sender.actor ! MessageResponse(
session,
ChatMsg(UNK_71, true, "", "@silence_disabled_ack", None),
ChatMsg(UNK_229, true, "", "@silence_disabled_ack", None),
channel
)
} else {
sender.actor ! MessageResponse(
session,
ChatMsg(UNK_71, true, "", "@silence_enabled_ack", None),
ChatMsg(UNK_229, true, "", "@silence_enabled_ack", None),
channel
)
}
@ -130,14 +130,14 @@ class ChatService(context: ActorContext[ChatService.Command]) extends AbstractBe
case None =>
sender.actor ! MessageResponse(
session,
ChatMsg(UNK_71, true, "", s"unknown player '$name'", None),
ChatMsg(UNK_229, true, "", s"unknown player '$name'", None),
channel
)
}
case (Some(sender), _, _, error) =>
sender.actor ! MessageResponse(
session,
ChatMsg(UNK_71, false, "", error.getOrElse("usage: /silence <name> [<time>]"), None),
ChatMsg(UNK_229, false, "", error.getOrElse("usage: /silence <name> [<time>]"), None),
channel
)