This commit is contained in:
dam 2026-04-29 22:19:49 +03:00
parent cdf43d01f8
commit 0d2f472d96
No known key found for this signature in database
GPG key ID: 4AF4E722399663FB

View file

@ -1,14 +1,17 @@
package content
import TestUtils
import core.ServerConstants
import core.game.node.entity.combat.CombatMovementIntents
import core.game.node.entity.combat.equipment.WeaponInterface
import core.game.node.entity.player.Player
import core.game.node.entity.skill.Skills
import core.game.world.GameWorld
import core.game.world.map.Location
import core.game.world.repository.Repository
import core.game.world.update.UpdateSequence
import core.net.packet.PacketProcessor
import core.tools.LogLevel
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Assertions.assertTrue
import org.junit.jupiter.api.Test
@ -21,56 +24,67 @@ class CombatPerformanceTests {
@Test
fun serverTickStaysWithinBudgetWithLiveSizedCombatLoad() {
val load = createCombatLoad()
withQuietPerformanceLogs {
var load: CombatLoad? = null
try {
load = createCombatLoad()
assertEquals(REAL_PLAYER_COUNT, load.players.count { !it.isArtificial })
assertEquals(BOT_PLAYER_COUNT, load.players.count { it.isArtificial })
repeat(WARMUP_TICKS) {
measureCombatTick(load, it)
}
val durations = LongArray(MEASURED_TICKS) { tick ->
measureCombatTick(load, tick + WARMUP_TICKS)
}
val sorted = durations.sorted()
val p90Index = ((sorted.size * 9 + 9) / 10 - 1).coerceIn(0, sorted.lastIndex)
val p90 = sorted[p90Index]
val max = sorted.last()
val durationText = durations.joinToString(prefix = "[", postfix = "]")
assertTrue(
p90 <= HEADROOM_TICK_BUDGET_MILLIS,
"650-player combat p90 tick time should leave room for slower live hardware. " +
"durations=${durationText}ms, p90=${p90}ms, " +
"budget=${HEADROOM_TICK_BUDGET_MILLIS}ms"
)
assertTrue(
max <= LIVE_TICK_BUDGET_MILLIS,
"650-player combat tick should remain under the live 600ms server tick budget. " +
"durations=${durationText}ms, max=${max}ms"
)
} finally {
load?.close()
}
}
}
private fun <T> withQuietPerformanceLogs(action: () -> T): T {
val previousLogLevel = ServerConstants.LOG_LEVEL
ServerConstants.LOG_LEVEL = LogLevel.CAUTIOUS
try {
assertEquals(REAL_PLAYER_COUNT, load.players.count { !it.isArtificial })
assertEquals(BOT_PLAYER_COUNT, load.players.count { it.isArtificial })
repeat(WARMUP_TICKS) {
measureCombatTick(load, it)
}
val durations = LongArray(MEASURED_TICKS) { tick ->
measureCombatTick(load, tick + WARMUP_TICKS)
}
val sorted = durations.sorted()
val p90Index = ((sorted.size * 9 + 9) / 10 - 1).coerceIn(0, sorted.lastIndex)
val p90 = sorted[p90Index]
val max = sorted.last()
val durationText = durations.joinToString(prefix = "[", postfix = "]")
assertTrue(
p90 <= HEADROOM_TICK_BUDGET_MILLIS,
"650-player combat p90 tick time should leave room for slower live hardware. " +
"durations=${durationText}ms, p90=${p90}ms, " +
"budget=${HEADROOM_TICK_BUDGET_MILLIS}ms"
)
assertTrue(
max <= LIVE_TICK_BUDGET_MILLIS,
"650-player combat tick should remain under the live 600ms server tick budget. " +
"durations=${durationText}ms, max=${max}ms"
)
return action()
} finally {
load.close()
ServerConstants.LOG_LEVEL = previousLogLevel
}
}
private fun createCombatLoad(): CombatLoad {
val players = ArrayList<Player>(TOTAL_PLAYER_COUNT)
val closeables = ArrayList<AutoCloseable>(TOTAL_PLAYER_COUNT)
val previousWildPvp = GameWorld.settings!!.wild_pvp_enabled
for (i in 0 until TOTAL_PLAYER_COUNT) {
val player = TestUtils.getMockPlayer("combat_perf_$i", isBot = i >= REAL_PLAYER_COUNT)
players.add(player)
closeables.add(player)
configureMeleePlayer(player)
}
val pairs = players.chunked(2).mapIndexed { index, pair ->
CombatPair(pair[0], pair[1], pairOrigin(index))
}
val load = CombatLoad(players, closeables, pairs, previousWildPvp)
val load = CombatLoad(players, pairs, previousWildPvp)
GameWorld.settings!!.wild_pvp_enabled = true
load.resetPairPositionsAndMovement(0)
@ -120,7 +134,6 @@ class CombatPerformanceTests {
private class CombatLoad(
val players: List<Player>,
private val closeables: List<AutoCloseable>,
private val pairs: List<CombatPair>,
private val previousWildPvp: Boolean
) : AutoCloseable {
@ -147,8 +160,13 @@ class CombatPerformanceTests {
override fun close() {
CombatMovementIntents.clear()
for (closeable in closeables.asReversed()) {
closeable.close()
for (player in players.asReversed()) {
player.pulseManager.clear()
player.walkingQueue.reset()
player.isActive = false
player.setPlaying(false)
Repository.removePlayer(player)
UpdateSequence.renderablePlayers.remove(player)
}
GameWorld.Pulser.updateAll()
UpdateSequence.renderablePlayers.sync()