mirror of
https://github.com/psforever/PSF-LoginServer.git
synced 2026-01-20 02:54:46 +00:00
Deconstruct in Privacy (#1069)
* when deconstructing at a spawn tube, eliminate damage by hiding the player character from rendering through psm manipulation; adjusts the psm load balancing algorithm; add conditions for checking for cancelling the deconstruction flag when certain actions are taken * condition for avoiding server-size (all) damage during deconstruction period * mutually assured discetion
This commit is contained in:
parent
90b7d2591d
commit
72572ad125
|
|
@ -69,27 +69,27 @@ class SessionAvatarHandlers(
|
|||
isJumping,
|
||||
jumpThrust,
|
||||
isCloaking,
|
||||
spectating,
|
||||
isNotRendered,
|
||||
canSeeReallyFar
|
||||
) if isNotSameTarget =>
|
||||
val pstateToSave = pstate.copy(timestamp = 0)
|
||||
val (lastMsg, lastTime, lastPosition, wasSpectating, wasVisible) = lastSeenStreamMessage(guid.guid) match {
|
||||
case SessionAvatarHandlers.LastUpstream(Some(msg), visible, time) => (Some(msg), time, msg.pos, msg.spectator, visible)
|
||||
case _ => (None, 0L, Vector3.Zero, false, false)
|
||||
val (lastMsg, lastTime, lastPosition, wasVisible) = lastSeenStreamMessage(guid.guid) match {
|
||||
case SessionAvatarHandlers.LastUpstream(Some(msg), visible, time) => (Some(msg), time, msg.pos, visible)
|
||||
case _ => (None, 0L, Vector3.Zero, false)
|
||||
}
|
||||
val drawConfig = Config.app.game.playerDraw
|
||||
val drawConfig = Config.app.game.playerDraw //m
|
||||
val maxRange = drawConfig.rangeMax * drawConfig.rangeMax //sq.m
|
||||
val ourPosition = player.Position
|
||||
val ourPosition = player.Position //xyz
|
||||
val currentDistance = Vector3.DistanceSquared(ourPosition, pos) //sq.m
|
||||
val inVisibleRange = currentDistance <= maxRange
|
||||
val wasInVisibleRange = Vector3.DistanceSquared(lastPosition, pos) <= maxRange
|
||||
val comingIntoVisibleRange = inVisibleRange && !wasInVisibleRange
|
||||
val inDrawableRange = currentDistance <= maxRange
|
||||
val now = System.currentTimeMillis() //ms
|
||||
val durationSince = now - lastTime //ms
|
||||
val released = player.isReleased
|
||||
if (!released &&
|
||||
!spectating &&
|
||||
(comingIntoVisibleRange || (inVisibleRange && !lastMsg.contains(pstateToSave)))) {
|
||||
if (
|
||||
sessionData.zoning.zoningStatus != Zoning.Status.Deconstructing &&
|
||||
!isNotRendered && inDrawableRange
|
||||
) {
|
||||
//conditions where visibility is assured
|
||||
val durationSince = now - lastTime //ms
|
||||
lazy val previouslyInDrawableRange = Vector3.DistanceSquared(ourPosition, lastPosition) <= maxRange
|
||||
lazy val targetDelay = {
|
||||
val populationOver = math.max(
|
||||
0,
|
||||
|
|
@ -102,12 +102,17 @@ class SessionAvatarHandlers(
|
|||
case index => drawConfig.delays(index)
|
||||
}
|
||||
} //ms
|
||||
if (comingIntoVisibleRange ||
|
||||
canSeeReallyFar ||
|
||||
currentDistance < drawConfig.rangeMin * drawConfig.rangeMin ||
|
||||
durationSince > drawConfig.delayMax ||
|
||||
sessionData.canSeeReallyFar ||
|
||||
durationSince > targetDelay) {
|
||||
if (!wasVisible ||
|
||||
!previouslyInDrawableRange ||
|
||||
(!lastMsg.contains(pstateToSave) &&
|
||||
(canSeeReallyFar ||
|
||||
currentDistance < drawConfig.rangeMin * drawConfig.rangeMin ||
|
||||
durationSince > drawConfig.delayMax ||
|
||||
sessionData.canSeeReallyFar ||
|
||||
durationSince > targetDelay
|
||||
)
|
||||
)
|
||||
) {
|
||||
//must draw
|
||||
sendResponse(
|
||||
PlayerStateMessage(
|
||||
|
|
@ -126,28 +131,31 @@ class SessionAvatarHandlers(
|
|||
)
|
||||
lastSeenStreamMessage(guid.guid) = SessionAvatarHandlers.LastUpstream(Some(pstateToSave), visible=true, now)
|
||||
} else {
|
||||
//is visible, but skip reinforcement
|
||||
lastSeenStreamMessage(guid.guid) = SessionAvatarHandlers.LastUpstream(Some(pstateToSave), visible=true, lastTime)
|
||||
}
|
||||
} else {
|
||||
//conditions where the target is not currently visible
|
||||
if (wasVisible) {
|
||||
//the target was JUST PREVIOUSLY visible; one last draw to move target beyond a renderable distance
|
||||
val lat = (1 + hidingPlayerRandomizer.nextInt(continent.map.scale.height.toInt)).toFloat
|
||||
sendResponse(
|
||||
PlayerStateMessage(
|
||||
guid,
|
||||
Vector3(1f, lat, 1f),
|
||||
vel=None,
|
||||
facingYaw=0f,
|
||||
facingPitch=0f,
|
||||
facingYawUpper=0f,
|
||||
timestamp=0, //is this okay?
|
||||
is_cloaked = isCloaking
|
||||
)
|
||||
)
|
||||
lastSeenStreamMessage(guid.guid) = SessionAvatarHandlers.LastUpstream(Some(pstateToSave), visible=false, now)
|
||||
} else {
|
||||
//skip drawing altogether
|
||||
lastSeenStreamMessage(guid.guid) = SessionAvatarHandlers.LastUpstream(Some(pstateToSave), visible=false, lastTime)
|
||||
}
|
||||
} else if (
|
||||
(!spectating && wasInVisibleRange && !inVisibleRange) ||
|
||||
(inVisibleRange && !wasSpectating && spectating) ||
|
||||
(wasVisible && released)
|
||||
) {
|
||||
//must hide
|
||||
val lat = (1 + hidingPlayerRandomizer.nextInt(continent.map.scale.height.toInt)).toFloat
|
||||
sendResponse(
|
||||
PlayerStateMessage(
|
||||
guid,
|
||||
Vector3(1f, lat, 1f),
|
||||
vel=None,
|
||||
facingYaw=0f,
|
||||
facingPitch=0f,
|
||||
facingYawUpper=0f,
|
||||
timestamp=0, //is this okay?
|
||||
is_cloaked = isCloaking
|
||||
)
|
||||
)
|
||||
lastSeenStreamMessage(guid.guid) = SessionAvatarHandlers.LastUpstream(Some(pstateToSave), visible=false, now)
|
||||
}
|
||||
|
||||
case AvatarResponse.ObjectHeld(slot, _)
|
||||
|
|
@ -157,6 +165,9 @@ class SessionAvatarHandlers(
|
|||
continent.GUID(sessionData.terminals.usingMedicalTerminal).collect {
|
||||
case term: Terminal with ProximityUnit => sessionData.terminals.StopUsingProximityUnit(term)
|
||||
}
|
||||
if (sessionData.zoning.zoningStatus == Zoning.Status.Deconstructing) {
|
||||
sessionData.stopDeconstructing()
|
||||
}
|
||||
|
||||
case AvatarResponse.ObjectHeld(slot, _)
|
||||
if isSameTarget && slot > -1 =>
|
||||
|
|
|
|||
|
|
@ -210,7 +210,11 @@ class SessionData(
|
|||
val isMoving = WorldEntity.isMoving(vel)
|
||||
val isMovingPlus = isMoving || isJumping || jumpThrust
|
||||
if (isMovingPlus) {
|
||||
zoning.CancelZoningProcessWithDescriptiveReason("cancel_motion")
|
||||
if (zoning.zoningStatus == Zoning.Status.Deconstructing) {
|
||||
stopDeconstructing()
|
||||
} else {
|
||||
zoning.CancelZoningProcessWithDescriptiveReason("cancel_motion")
|
||||
}
|
||||
}
|
||||
fallHeightTracker(pos.z)
|
||||
// if (isCrouching && !player.Crouching) {
|
||||
|
|
@ -258,6 +262,9 @@ class SessionData(
|
|||
case None => ()
|
||||
}
|
||||
val eagleEye: Boolean = canSeeReallyFar
|
||||
val isNotVisible: Boolean = player.spectator ||
|
||||
zoning.zoningStatus == Zoning.Status.Deconstructing ||
|
||||
(player.isAlive && zoning.spawn.deadState == DeadState.RespawnTime)
|
||||
continent.AvatarEvents ! AvatarServiceMessage(
|
||||
continent.id,
|
||||
AvatarAction.PlayerState(
|
||||
|
|
@ -272,7 +279,7 @@ class SessionData(
|
|||
isJumping,
|
||||
jumpThrust,
|
||||
isCloaking,
|
||||
player.spectator,
|
||||
isNotVisible,
|
||||
eagleEye
|
||||
)
|
||||
)
|
||||
|
|
@ -516,15 +523,27 @@ class SessionData(
|
|||
def handleAvatarImplant(pkt: AvatarImplantMessage): Unit = {
|
||||
val AvatarImplantMessage(_, action, slot, status) = pkt
|
||||
if (action == ImplantAction.Activation) {
|
||||
zoning.CancelZoningProcessWithDescriptiveReason("cancel_implant")
|
||||
avatar.implants(slot) match {
|
||||
case Some(implant) =>
|
||||
if (status == 1) {
|
||||
avatarActor ! AvatarActor.ActivateImplant(implant.definition.implantType)
|
||||
} else {
|
||||
if (zoning.zoningStatus == Zoning.Status.Deconstructing) {
|
||||
//do not activate; play deactivation sound instead
|
||||
stopDeconstructing()
|
||||
avatar.implants(slot).collect {
|
||||
case implant if implant.active =>
|
||||
avatarActor ! AvatarActor.DeactivateImplant(implant.definition.implantType)
|
||||
}
|
||||
case _ => log.error(s"AvatarImplantMessage: ${player.Name} has an unknown implant in $slot")
|
||||
case implant =>
|
||||
sendResponse(PlanetsideAttributeMessage(player.GUID, 28, implant.definition.implantType.value * 2))
|
||||
}
|
||||
} else {
|
||||
zoning.CancelZoningProcessWithDescriptiveReason("cancel_implant")
|
||||
avatar.implants(slot) match {
|
||||
case Some(implant) =>
|
||||
if (status == 1) {
|
||||
avatarActor ! AvatarActor.ActivateImplant(implant.definition.implantType)
|
||||
} else {
|
||||
avatarActor ! AvatarActor.DeactivateImplant(implant.definition.implantType)
|
||||
}
|
||||
case _ =>
|
||||
log.error(s"AvatarImplantMessage: ${player.Name} has an unknown implant in $slot")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1422,11 +1441,10 @@ class SessionData(
|
|||
sendUseGeneralEntityMessage(obj, item)
|
||||
case None if player.Faction == obj.Faction =>
|
||||
//deconstruction
|
||||
log.info(s"${player.Name} is deconstructing at the ${obj.Owner.Definition.Name}'s spawns")
|
||||
zoning.CancelZoningProcessWithDescriptiveReason("cancel_use")
|
||||
playerActionsToCancel()
|
||||
terminals.CancelAllProximityUnits()
|
||||
zoning.spawn.GoToDeploymentMap()
|
||||
startDeconstructing(obj)
|
||||
case _ => ()
|
||||
}
|
||||
}
|
||||
|
|
@ -2751,6 +2769,34 @@ class SessionData(
|
|||
sendResponse(ChatMsg(ChatMessageType.UNK_227, wideContents=false, "", "@charsaved", None))
|
||||
}
|
||||
|
||||
def startDeconstructing(obj: SpawnTube): Unit = {
|
||||
log.info(s"${player.Name} is deconstructing at the ${obj.Owner.Definition.Name}'s spawns")
|
||||
avatar.implants.collect {
|
||||
case Some(implant) if implant.active && !implant.definition.Passive =>
|
||||
avatarActor ! AvatarActor.DeactivateImplant(implant.definition.implantType)
|
||||
}
|
||||
if (player.ExoSuit != ExoSuitType.MAX) {
|
||||
player.Actor ! PlayerControl.ObjectHeld(Player.HandsDownSlot, updateMyHolsterArm = true)
|
||||
}
|
||||
zoning.spawn.nextSpawnPoint = Some(obj) //set fallback
|
||||
zoning.zoningStatus = Zoning.Status.Deconstructing
|
||||
player.allowInteraction = false
|
||||
if (player.death_by == 0) {
|
||||
player.death_by = 1
|
||||
}
|
||||
zoning.spawn.GoToDeploymentMap()
|
||||
}
|
||||
|
||||
def stopDeconstructing(): Unit = {
|
||||
zoning.zoningStatus = Zoning.Status.None
|
||||
player.death_by = math.min(player.death_by, 0)
|
||||
player.allowInteraction = true
|
||||
zoning.spawn.nextSpawnPoint.foreach { tube =>
|
||||
sendResponse(PlayerStateShiftMessage(ShiftState(0, tube.Position, tube.Orientation.z)))
|
||||
zoning.spawn.nextSpawnPoint = None
|
||||
}
|
||||
}
|
||||
|
||||
def failWithError(error: String): Unit = {
|
||||
log.error(error)
|
||||
middlewareActor ! MiddlewareActor.Teardown()
|
||||
|
|
|
|||
|
|
@ -1920,6 +1920,9 @@ class ZoningOperations(
|
|||
TurnCounterDuringInterim
|
||||
}
|
||||
sessionData.keepAliveFunc = NormalKeepAlive
|
||||
if (zoningStatus == Zoning.Status.Deconstructing) {
|
||||
sessionData.stopDeconstructing()
|
||||
}
|
||||
upstreamMessageCount = 0
|
||||
setAvatar = false
|
||||
sessionData.persist()
|
||||
|
|
@ -1950,6 +1953,9 @@ class ZoningOperations(
|
|||
TurnCounterDuringInterim
|
||||
}
|
||||
sessionData.keepAliveFunc = NormalKeepAlive
|
||||
if (zoningStatus == Zoning.Status.Deconstructing) {
|
||||
sessionData.stopDeconstructing()
|
||||
}
|
||||
upstreamMessageCount = 0
|
||||
setAvatar = false
|
||||
sessionData.persist()
|
||||
|
|
@ -2080,6 +2086,7 @@ class ZoningOperations(
|
|||
player.Health = health
|
||||
player.Armor = armor
|
||||
}
|
||||
player.death_by = math.min(player.death_by, 0)
|
||||
sessionData.vehicles.GetKnownVehicleAndSeat() match {
|
||||
case (Some(vehicle: Vehicle), Some(seat: Int)) =>
|
||||
//if the vehicle is the cargo of another vehicle in this zone
|
||||
|
|
|
|||
|
|
@ -547,6 +547,10 @@ class Player(var avatar: Avatar)
|
|||
ZoningRequest
|
||||
}
|
||||
|
||||
override def CanDamage: Boolean = {
|
||||
death_by < 1 && super.CanDamage
|
||||
}
|
||||
|
||||
def DamageModel: DamageResistanceModel = exosuit.asInstanceOf[DamageResistanceModel]
|
||||
|
||||
def canEqual(other: Any): Boolean = other.isInstanceOf[Player]
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ object Zoning {
|
|||
val values: IndexedSeq[Status] = findValues
|
||||
|
||||
case object None extends Status(value = "None")
|
||||
case object Deconstructing extends Status(value = "Deconstructing")
|
||||
case object Request extends Status(value = "Request")
|
||||
case object Countdown extends Status(value = "Countdown")
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue