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-pragma run configuration in IntelliJ
  2. Start the run-load-simulator run configuration in IntelliJ
[game]-load-simulator/src/main/kotlin/LoadSimulatorMain.kt
package pragma.loadsimulator

import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.runBlocking
import pragma.party.PartyRpc.CreateV1Request
import pragma.party.PartyRpc.CreateV1Response
import pragma.party.PartyRpc.JoinWithInviteCodeV1Request
import pragma.party.PartyRpc.JoinWithInviteCodeV1Response
import pragma.utils.toUUID

@ExperimentalCoroutinesApi
fun main() {

    // Initialize your config. Override values as desired, later you can parse a config file passed
    // in as an argument.
    val config = LoadSimulatorConfig(totalPlayerCount = 3)

    // Run within a coroutine scope to initialize and start the scenario.
    runBlocking {

        // Build the runner with a list of phases, the building blocks of your scenario
        val runner = LoadSimulatorRunner.build(config, this, ::generatePhases)

        runner.runScenario()
    }
}

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

        // This builder accepts a list of steps to run sequentially
        Phase.buildWithSteps(
            "ExamplePhase",
            context,
            listOf(
                // Scenario code lives within steps. The specified player count will be passed to
                // each step execution.
                ExampleStep(context, 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 an rpc
        // error or application error.
        val party =
            leader.game
                .sendOrThrowV2(
                    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.error.name}")
                }

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