mirror of
https://github.com/2revoemag/PSF-BotServer.git
synced 2026-07-13 07:24:53 +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
5 changed files with 121 additions and 52 deletions
|
|
@ -69,27 +69,27 @@ class SessionAvatarHandlers(
|
||||||
isJumping,
|
isJumping,
|
||||||
jumpThrust,
|
jumpThrust,
|
||||||
isCloaking,
|
isCloaking,
|
||||||
spectating,
|
isNotRendered,
|
||||||
canSeeReallyFar
|
canSeeReallyFar
|
||||||
) if isNotSameTarget =>
|
) if isNotSameTarget =>
|
||||||
val pstateToSave = pstate.copy(timestamp = 0)
|
val pstateToSave = pstate.copy(timestamp = 0)
|
||||||
val (lastMsg, lastTime, lastPosition, wasSpectating, wasVisible) = lastSeenStreamMessage(guid.guid) match {
|
val (lastMsg, lastTime, lastPosition, wasVisible) = lastSeenStreamMessage(guid.guid) match {
|
||||||
case SessionAvatarHandlers.LastUpstream(Some(msg), visible, time) => (Some(msg), time, msg.pos, msg.spectator, visible)
|
case SessionAvatarHandlers.LastUpstream(Some(msg), visible, time) => (Some(msg), time, msg.pos, visible)
|
||||||
case _ => (None, 0L, Vector3.Zero, false, false)
|
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 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 currentDistance = Vector3.DistanceSquared(ourPosition, pos) //sq.m
|
||||||
val inVisibleRange = currentDistance <= maxRange
|
val inDrawableRange = currentDistance <= maxRange
|
||||||
val wasInVisibleRange = Vector3.DistanceSquared(lastPosition, pos) <= maxRange
|
|
||||||
val comingIntoVisibleRange = inVisibleRange && !wasInVisibleRange
|
|
||||||
val now = System.currentTimeMillis() //ms
|
val now = System.currentTimeMillis() //ms
|
||||||
val durationSince = now - lastTime //ms
|
if (
|
||||||
val released = player.isReleased
|
sessionData.zoning.zoningStatus != Zoning.Status.Deconstructing &&
|
||||||
if (!released &&
|
!isNotRendered && inDrawableRange
|
||||||
!spectating &&
|
) {
|
||||||
(comingIntoVisibleRange || (inVisibleRange && !lastMsg.contains(pstateToSave)))) {
|
//conditions where visibility is assured
|
||||||
|
val durationSince = now - lastTime //ms
|
||||||
|
lazy val previouslyInDrawableRange = Vector3.DistanceSquared(ourPosition, lastPosition) <= maxRange
|
||||||
lazy val targetDelay = {
|
lazy val targetDelay = {
|
||||||
val populationOver = math.max(
|
val populationOver = math.max(
|
||||||
0,
|
0,
|
||||||
|
|
@ -102,12 +102,17 @@ class SessionAvatarHandlers(
|
||||||
case index => drawConfig.delays(index)
|
case index => drawConfig.delays(index)
|
||||||
}
|
}
|
||||||
} //ms
|
} //ms
|
||||||
if (comingIntoVisibleRange ||
|
if (!wasVisible ||
|
||||||
canSeeReallyFar ||
|
!previouslyInDrawableRange ||
|
||||||
currentDistance < drawConfig.rangeMin * drawConfig.rangeMin ||
|
(!lastMsg.contains(pstateToSave) &&
|
||||||
durationSince > drawConfig.delayMax ||
|
(canSeeReallyFar ||
|
||||||
sessionData.canSeeReallyFar ||
|
currentDistance < drawConfig.rangeMin * drawConfig.rangeMin ||
|
||||||
durationSince > targetDelay) {
|
durationSince > drawConfig.delayMax ||
|
||||||
|
sessionData.canSeeReallyFar ||
|
||||||
|
durationSince > targetDelay
|
||||||
|
)
|
||||||
|
)
|
||||||
|
) {
|
||||||
//must draw
|
//must draw
|
||||||
sendResponse(
|
sendResponse(
|
||||||
PlayerStateMessage(
|
PlayerStateMessage(
|
||||||
|
|
@ -126,28 +131,31 @@ class SessionAvatarHandlers(
|
||||||
)
|
)
|
||||||
lastSeenStreamMessage(guid.guid) = SessionAvatarHandlers.LastUpstream(Some(pstateToSave), visible=true, now)
|
lastSeenStreamMessage(guid.guid) = SessionAvatarHandlers.LastUpstream(Some(pstateToSave), visible=true, now)
|
||||||
} else {
|
} 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)
|
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, _)
|
case AvatarResponse.ObjectHeld(slot, _)
|
||||||
|
|
@ -157,6 +165,9 @@ class SessionAvatarHandlers(
|
||||||
continent.GUID(sessionData.terminals.usingMedicalTerminal).collect {
|
continent.GUID(sessionData.terminals.usingMedicalTerminal).collect {
|
||||||
case term: Terminal with ProximityUnit => sessionData.terminals.StopUsingProximityUnit(term)
|
case term: Terminal with ProximityUnit => sessionData.terminals.StopUsingProximityUnit(term)
|
||||||
}
|
}
|
||||||
|
if (sessionData.zoning.zoningStatus == Zoning.Status.Deconstructing) {
|
||||||
|
sessionData.stopDeconstructing()
|
||||||
|
}
|
||||||
|
|
||||||
case AvatarResponse.ObjectHeld(slot, _)
|
case AvatarResponse.ObjectHeld(slot, _)
|
||||||
if isSameTarget && slot > -1 =>
|
if isSameTarget && slot > -1 =>
|
||||||
|
|
|
||||||
|
|
@ -210,7 +210,11 @@ class SessionData(
|
||||||
val isMoving = WorldEntity.isMoving(vel)
|
val isMoving = WorldEntity.isMoving(vel)
|
||||||
val isMovingPlus = isMoving || isJumping || jumpThrust
|
val isMovingPlus = isMoving || isJumping || jumpThrust
|
||||||
if (isMovingPlus) {
|
if (isMovingPlus) {
|
||||||
zoning.CancelZoningProcessWithDescriptiveReason("cancel_motion")
|
if (zoning.zoningStatus == Zoning.Status.Deconstructing) {
|
||||||
|
stopDeconstructing()
|
||||||
|
} else {
|
||||||
|
zoning.CancelZoningProcessWithDescriptiveReason("cancel_motion")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
fallHeightTracker(pos.z)
|
fallHeightTracker(pos.z)
|
||||||
// if (isCrouching && !player.Crouching) {
|
// if (isCrouching && !player.Crouching) {
|
||||||
|
|
@ -258,6 +262,9 @@ class SessionData(
|
||||||
case None => ()
|
case None => ()
|
||||||
}
|
}
|
||||||
val eagleEye: Boolean = canSeeReallyFar
|
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.AvatarEvents ! AvatarServiceMessage(
|
||||||
continent.id,
|
continent.id,
|
||||||
AvatarAction.PlayerState(
|
AvatarAction.PlayerState(
|
||||||
|
|
@ -272,7 +279,7 @@ class SessionData(
|
||||||
isJumping,
|
isJumping,
|
||||||
jumpThrust,
|
jumpThrust,
|
||||||
isCloaking,
|
isCloaking,
|
||||||
player.spectator,
|
isNotVisible,
|
||||||
eagleEye
|
eagleEye
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
@ -516,15 +523,27 @@ class SessionData(
|
||||||
def handleAvatarImplant(pkt: AvatarImplantMessage): Unit = {
|
def handleAvatarImplant(pkt: AvatarImplantMessage): Unit = {
|
||||||
val AvatarImplantMessage(_, action, slot, status) = pkt
|
val AvatarImplantMessage(_, action, slot, status) = pkt
|
||||||
if (action == ImplantAction.Activation) {
|
if (action == ImplantAction.Activation) {
|
||||||
zoning.CancelZoningProcessWithDescriptiveReason("cancel_implant")
|
if (zoning.zoningStatus == Zoning.Status.Deconstructing) {
|
||||||
avatar.implants(slot) match {
|
//do not activate; play deactivation sound instead
|
||||||
case Some(implant) =>
|
stopDeconstructing()
|
||||||
if (status == 1) {
|
avatar.implants(slot).collect {
|
||||||
avatarActor ! AvatarActor.ActivateImplant(implant.definition.implantType)
|
case implant if implant.active =>
|
||||||
} else {
|
|
||||||
avatarActor ! AvatarActor.DeactivateImplant(implant.definition.implantType)
|
avatarActor ! AvatarActor.DeactivateImplant(implant.definition.implantType)
|
||||||
}
|
case implant =>
|
||||||
case _ => log.error(s"AvatarImplantMessage: ${player.Name} has an unknown implant in $slot")
|
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)
|
sendUseGeneralEntityMessage(obj, item)
|
||||||
case None if player.Faction == obj.Faction =>
|
case None if player.Faction == obj.Faction =>
|
||||||
//deconstruction
|
//deconstruction
|
||||||
log.info(s"${player.Name} is deconstructing at the ${obj.Owner.Definition.Name}'s spawns")
|
|
||||||
zoning.CancelZoningProcessWithDescriptiveReason("cancel_use")
|
zoning.CancelZoningProcessWithDescriptiveReason("cancel_use")
|
||||||
playerActionsToCancel()
|
playerActionsToCancel()
|
||||||
terminals.CancelAllProximityUnits()
|
terminals.CancelAllProximityUnits()
|
||||||
zoning.spawn.GoToDeploymentMap()
|
startDeconstructing(obj)
|
||||||
case _ => ()
|
case _ => ()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2751,6 +2769,34 @@ class SessionData(
|
||||||
sendResponse(ChatMsg(ChatMessageType.UNK_227, wideContents=false, "", "@charsaved", None))
|
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 = {
|
def failWithError(error: String): Unit = {
|
||||||
log.error(error)
|
log.error(error)
|
||||||
middlewareActor ! MiddlewareActor.Teardown()
|
middlewareActor ! MiddlewareActor.Teardown()
|
||||||
|
|
|
||||||
|
|
@ -1920,6 +1920,9 @@ class ZoningOperations(
|
||||||
TurnCounterDuringInterim
|
TurnCounterDuringInterim
|
||||||
}
|
}
|
||||||
sessionData.keepAliveFunc = NormalKeepAlive
|
sessionData.keepAliveFunc = NormalKeepAlive
|
||||||
|
if (zoningStatus == Zoning.Status.Deconstructing) {
|
||||||
|
sessionData.stopDeconstructing()
|
||||||
|
}
|
||||||
upstreamMessageCount = 0
|
upstreamMessageCount = 0
|
||||||
setAvatar = false
|
setAvatar = false
|
||||||
sessionData.persist()
|
sessionData.persist()
|
||||||
|
|
@ -1950,6 +1953,9 @@ class ZoningOperations(
|
||||||
TurnCounterDuringInterim
|
TurnCounterDuringInterim
|
||||||
}
|
}
|
||||||
sessionData.keepAliveFunc = NormalKeepAlive
|
sessionData.keepAliveFunc = NormalKeepAlive
|
||||||
|
if (zoningStatus == Zoning.Status.Deconstructing) {
|
||||||
|
sessionData.stopDeconstructing()
|
||||||
|
}
|
||||||
upstreamMessageCount = 0
|
upstreamMessageCount = 0
|
||||||
setAvatar = false
|
setAvatar = false
|
||||||
sessionData.persist()
|
sessionData.persist()
|
||||||
|
|
@ -2080,6 +2086,7 @@ class ZoningOperations(
|
||||||
player.Health = health
|
player.Health = health
|
||||||
player.Armor = armor
|
player.Armor = armor
|
||||||
}
|
}
|
||||||
|
player.death_by = math.min(player.death_by, 0)
|
||||||
sessionData.vehicles.GetKnownVehicleAndSeat() match {
|
sessionData.vehicles.GetKnownVehicleAndSeat() match {
|
||||||
case (Some(vehicle: Vehicle), Some(seat: Int)) =>
|
case (Some(vehicle: Vehicle), Some(seat: Int)) =>
|
||||||
//if the vehicle is the cargo of another vehicle in this zone
|
//if the vehicle is the cargo of another vehicle in this zone
|
||||||
|
|
|
||||||
|
|
@ -547,6 +547,10 @@ class Player(var avatar: Avatar)
|
||||||
ZoningRequest
|
ZoningRequest
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override def CanDamage: Boolean = {
|
||||||
|
death_by < 1 && super.CanDamage
|
||||||
|
}
|
||||||
|
|
||||||
def DamageModel: DamageResistanceModel = exosuit.asInstanceOf[DamageResistanceModel]
|
def DamageModel: DamageResistanceModel = exosuit.asInstanceOf[DamageResistanceModel]
|
||||||
|
|
||||||
def canEqual(other: Any): Boolean = other.isInstanceOf[Player]
|
def canEqual(other: Any): Boolean = other.isInstanceOf[Player]
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@ object Zoning {
|
||||||
val values: IndexedSeq[Status] = findValues
|
val values: IndexedSeq[Status] = findValues
|
||||||
|
|
||||||
case object None extends Status(value = "None")
|
case object None extends Status(value = "None")
|
||||||
|
case object Deconstructing extends Status(value = "Deconstructing")
|
||||||
case object Request extends Status(value = "Request")
|
case object Request extends Status(value = "Request")
|
||||||
case object Countdown extends Status(value = "Countdown")
|
case object Countdown extends Status(value = "Countdown")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue