Skip to content

Commit

Permalink
feat: allow players to be marked as high pri. relative to one another…
Browse files Browse the repository at this point in the history
… (v225 only)

Allows players to mark one another as high priority, meaning they will
render that specific player above large crowds of players, even if they
would not ordinarily fit the distance criteria. This is an addition to
the default high priority system in the previous commit, which allows
specific users to be marked as high priority to everyone.

The specific use cases here would be to mark players in combat between
one another as high priority, ensuring both of them can see each-other.
However, to do this properly, the value must also be reset when combat
ends between them. This is just an example use case and Jagex does not
actually do it, but servers may wish. An additional example could be
to always render anyone on your friend list over anyone else, or for
example your own clan members. One needs to be careful with this though,
as both of those systems allow potentially for hundreds of members,
which goes above the typical preferred count of 250.
  • Loading branch information
Z-Kris committed Sep 28, 2024
1 parent 53f1821 commit 6613d0c
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ public class PlayerAvatar internal constructor(
extendedInfoWriters: List<AvatarExtendedInfoWriter<PlayerExtendedInfoEncoders, PlayerAvatarExtendedInfoBlocks>>,
huffmanCodec: HuffmanCodecProvider,
) : Avatar {
/**
* The index of our local player.
*/
internal var localPlayerIndex: Int = localIndex

/**
* The preferred resize range. The player information protocol will attempt to
* add everyone within [preferredResizeRange] tiles to high resolution.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,13 @@ public class PlayerInfo internal constructor(
*/
private var extendedInfoCount: Int = 0

/**
* A bitset of high priority players. These players will be rendered above typical crowd
* when our resize range begins to decrement, as long as the given player is still within
* the preferred resize range threshold.
*/
private val highPriorityPlayers: LongArray = LongArray(PROTOCOL_CAPACITY ushr 6)

/**
* The flags indicating the status of the players in the previous and current cycles.
* This is used to categorize players who are 'stationary', which implies they did not
Expand Down Expand Up @@ -181,6 +188,61 @@ public class PlayerInfo internal constructor(

override fun isDestroyed(): Boolean = this.exception != null

/**
* Sets the [otherPlayerAvatar] as high priority for us specifically.
* This means that when our local player count gets to >= 250 players,
* we will still keep that player rendered even if they are no longer within
* the range that we can still see to. It does not, however, extend past the
* preferred view range.
* @param otherPlayerAvatar the avatar to mark as high priority in relation to us.
*/
public fun setHighPriority(otherPlayerAvatar: PlayerAvatar) {
this.setHighPriority(otherPlayerAvatar.localPlayerIndex)
}

/**
* Sets the [otherPlayerAvatar] back down to normal priority level, meaning
* they will not get preferential treatment in relation to everyone else
* at high populations, as described in [setHighPriority].
* @param otherPlayerAvatar the avatar to mark back down to normal priority.
*/
public fun setNormalPriority(otherPlayerAvatar: PlayerAvatar) {
this.unsetHighPriority(otherPlayerAvatar.localPlayerIndex)
}

/**
* Checks whether the player avatar at the specified [index] is high priority.
* @param index the index of the player to check.
* @return whether the checked player is high priority.
*/
private fun isHighPriority(index: Int): Boolean {
val longIndex = index ushr 6
val bit = 1L shl (index and 0x3F)
return this.highPriorityPlayers[longIndex] and bit != 0L
}

/**
* Sets the player at the specified [index] as high priority.
* @param index the index of the player to mark as high priority.
*/
private fun setHighPriority(index: Int) {
val longIndex = index ushr 6
val bit = 1L shl (index and 0x3F)
val cur = this.highPriorityPlayers[longIndex]
this.highPriorityPlayers[longIndex] = cur or bit
}

/**
* Sets the player at the specified [index] as normal priority.
* @param index the index of the player to mark as normal priority.
*/
internal fun unsetHighPriority(index: Int) {
val longIndex = index ushr 6
val bit = 1L shl (index and 0x3F)
val cur = this.highPriorityPlayers[longIndex]
this.highPriorityPlayers[longIndex] = cur and bit.inv()
}

/**
* Updates the render coordinate for the provided world id.
* This coordinate is what will be used to perform distance checks between the player
Expand Down Expand Up @@ -842,7 +904,9 @@ public class PlayerInfo internal constructor(
val details = getDetailsOrNull(worldId) ?: return false
val coord = other.avatar.currentCoord
val rangeToCheck =
if (other.avatar.priority == AvatarPriority.NORMAL) {
if (other.avatar.priority == AvatarPriority.NORMAL ||
isHighPriority(other.avatar.localPlayerIndex)
) {
this.avatar.preferredResizeRange
} else {
this.avatar.resizeRange
Expand Down Expand Up @@ -877,7 +941,9 @@ public class PlayerInfo internal constructor(
val details = getDetailsOrNull(worldId) ?: return false
val coord = other.avatar.currentCoord
val rangeToCheck =
if (other.avatar.priority == AvatarPriority.NORMAL) {
if (other.avatar.priority == AvatarPriority.NORMAL ||
isHighPriority(other.avatar.localPlayerIndex)
) {
this.avatar.preferredResizeRange
} else {
this.avatar.resizeRange
Expand Down Expand Up @@ -938,6 +1004,7 @@ public class PlayerInfo internal constructor(
newInstance: Boolean,
) {
this.localIndex = index
avatar.localPlayerIndex = index
avatar.extendedInfo.localIndex = index
this.oldSchoolClientType = oldSchoolClientType
avatar.reset()
Expand All @@ -948,6 +1015,7 @@ public class PlayerInfo internal constructor(
highResolutionCount = 0
highResolutionPlayers.fill(0L)
highResolutionExtendedInfoTrackedPlayers.fill(0L)
highPriorityPlayers.fill(0L)
extendedInfoCount = 0
extendedInfoIndices.fill(0)
stationary.fill(0)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,15 @@ public class PlayerInfoProtocol(
if (info.isDestroyed()) {
return
}
playerInfoRepository.dealloc(info.localIndex)
val index = info.localIndex
// Reset the high priority property on everyone that might be observing us
// Including ourselves (not that this matters, but since we allow it, we must do
// this step before the dealloc call).
for (i in 0..<PROTOCOL_CAPACITY) {
val otherInfo = playerInfoRepository.getOrNull(i) ?: continue
otherInfo.unsetHighPriority(index)
}
playerInfoRepository.dealloc(index)
}

/**
Expand Down

0 comments on commit 6613d0c

Please sign in to comment.