Getting Started with the Load Simulator #

This Getting Started Guide provides an example scenario and how to run locally.

Example #

The generated file: [game]-load-simulator/src/main/kotlin/LoadSimulatorMain.kt comes with a working scenario.

  1. Start the run - [game] - BOTH run configuration in IntelliJ
  2. Start the run-load-simulator run configuration in IntelliJ
[game]-load-simulator/src/main/kotlin/LoadSimulatorMain.kt
import kotlin.system.exitProcess
import kotlinx.coroutines.runBlocking
import pragma.loadsimulator.ClientWrapper
import pragma.loadsimulator.ICustomStepTracker
import pragma.loadsimulator.LoadSimulatorConfigLoader
import pragma.loadsimulator.LoadSimulatorContext
import pragma.loadsimulator.LoadSimulatorRunner
import pragma.loadsimulator.Phase
import pragma.loadsimulator.Step
import pragma.party.PartyCommon.PartyApplicationError
import pragma.party.PartyRpc.CreateV1Request
import pragma.party.PartyRpc.CreateV1Response
import pragma.party.PartyRpc.JoinWithInviteCodeV1Request
import pragma.party.PartyRpc.JoinWithInviteCodeV1Response
import pragma.utils.toUUID

fun main(args: Array<String>): Unit = runBlocking {
    val config = LoadSimulatorConfigLoader().load(args)
    val runner = LoadSimulatorRunner.build(config, this, ::generatePhases)
    val exitCode = runner.runScenario()
    exitProcess(exitCode.ordinal)
}

fun generatePhases(loadSimulatorContext: LoadSimulatorContext): List<Phase> {
    return listOf(

        // This builder accepts a list of steps to run sequentially
        Phase.buildWithSteps(
            "ExamplePhase",
            loadSimulatorContext,
            listOf(
                // Scenario code lives within steps. The specified player count will be passed to each step execution.
                ExampleStep(loadSimulatorContext, playerCount = 3),
            ),
            // Run the phase a specified number of times.
            runCount = 1,
        ),
    )
}

class ExampleStep(context: LoadSimulatorContext, playerCount: Int) : Step("ExampleStep", context, playerCount) {
    override suspend fun runStep(players: List<ClientWrapper>, tracker: ICustomStepTracker) {

        //The runner will pass in the correct number of players guaranteed.
        val leader = players[0]
        val buddies = players.subList(1, players.size)

        // sendOrThrow will return the response object or throw an exception in the event of a service error, application error, or connection failure.
        val party = leader.game.sendOrThrow(CreateV1Request.getDefaultInstance(), CreateV1Response::class, tracker).party
        println("Your partyId is: ${party.partyId.toUUID()}")

        val joinRequest = JoinWithInviteCodeV1Request.newBuilder().setInviteCode(party.inviteCode).build()
        buddies.forEach { buddy ->

            // send will invoke an error callback and return null on error
            val result = buddy.game.send(joinRequest, JoinWithInviteCodeV1Response::class, tracker) { f ->
                println("oh no, an error! ${(f.failure as? PartyApplicationError)?.error?.name ?: f.failure}")
            }

            if (result != null) {
                val partySnapshot = result.party
                println("Your party includes: ${partySnapshot.partyMembersList.joinToString { it.displayName.displayName }}")
            }
        }
    }
}