Skip to content

Commit

Permalink
Merge pull request #254 from iv4xr-project/astronaut-statistics
Browse files Browse the repository at this point in the history
Astronaut statistics
  • Loading branch information
hovi authored Jan 4, 2023
2 parents 0ae60a9 + baa0985 commit 925992e
Show file tree
Hide file tree
Showing 59 changed files with 943 additions and 167 deletions.
41 changes: 37 additions & 4 deletions CucumberTester/src/main/kotlin/bdd/CharacterActions.kt
Original file line number Diff line number Diff line change
@@ -1,25 +1,39 @@
package bdd

import bdd.connection.ConnectionManager
import bdd.setup.connectClientsDirectly
import bdd.setup.connectToFirstFriendlyGame
import bdd.setup.createLobbyGame
import bdd.setup.dieAndConfirm
import bdd.setup.exitToMainMenu
import io.cucumber.java.PendingException
import io.cucumber.java.en.Given
import io.cucumber.java.en.Then
import io.cucumber.java.en.When
import kotlinx.coroutines.delay
import kotlinx.coroutines.runBlocking
import bdd.connection.ConnectionManager
import spaceEngineers.controller.extensions.blockingMoveForwardByDistance
import spaceEngineers.controller.extensions.grindDownToPercentage
import spaceEngineers.controller.extensions.toNullIfMinusOne
import spaceEngineers.controller.extensions.torchBackToMax
import spaceEngineers.model.*
import spaceEngineers.model.Block
import spaceEngineers.model.CharacterMovement
import spaceEngineers.model.CharacterMovementType
import spaceEngineers.model.DataToolbarItemDefinition
import spaceEngineers.model.DefinitionId
import spaceEngineers.model.DefinitionId.Companion.ID_PREFIX
import spaceEngineers.model.ToolbarLocation
import spaceEngineers.model.Vec2F
import spaceEngineers.model.Vec3F
import spaceEngineers.model.extensions.allBlocks
import spaceEngineers.model.extensions.normalizeAsRun
import spaceEngineers.movement.*
import spaceEngineers.movement.CompositeDirection3d
import spaceEngineers.movement.FrameSnapshot
import spaceEngineers.movement.InputSnapshot
import spaceEngineers.movement.KeyboardSnapshot
import spaceEngineers.movement.MouseButton
import spaceEngineers.movement.ReplayMovement
import spaceEngineers.movement.VectorMovement
import kotlin.test.assertEquals


Expand Down Expand Up @@ -118,7 +132,8 @@ class CharacterActions(connectionManager: ConnectionManager) : AbstractMultiplay
val toolbarLocation =
toolbar.findLocation(blockType) ?: error("cannot find $blockType in toolbar")
val definitionId =
toolbar.items.filterIsInstance<DataToolbarItemDefinition>().firstOrNull { it.id.type == blockType }?.id ?: error("Cannot find $blockType in toolbar")
toolbar.items.filterIsInstance<DataToolbarItemDefinition>().firstOrNull { it.id.type == blockType }?.id
?: error("Cannot find $blockType in toolbar")
items.setToolbarItem(definitionId, toolbarLocation)
items.equip(toolbarLocation)
delay(150)
Expand Down Expand Up @@ -462,4 +477,22 @@ class CharacterActions(connectionManager: ConnectionManager) : AbstractMultiplay
)
}

@When("Character opens helmet.")
fun character_opens_helmet() {
mainClient {
character.setHelmet(false)
}

}

@When("Character turns on personal light.")
fun character_turns_on_personal_light() = mainClient {
character.setLight(true)
println(screens.gamePlay.data().hud.stats)
}

@When("Character suicides.")
fun character_suicides() = mainClient {
dieAndConfirm()
}
}
172 changes: 166 additions & 6 deletions CucumberTester/src/main/kotlin/bdd/CharacterAsserts.kt
Original file line number Diff line number Diff line change
@@ -1,19 +1,43 @@
package bdd

import bdd.connection.ConnectionManager
import bdd.connection.ProcessWithConnection
import bdd.repetitiveassert.repeatUntilSuccess
import io.cucumber.datatable.DataTable
import io.cucumber.java.PendingException
import io.cucumber.java.en.And
import io.cucumber.java.en.Given
import io.cucumber.java.en.Then
import io.cucumber.java.en.When
import kotlinx.coroutines.delay
import bdd.connection.ConnectionManager
import bdd.connection.ProcessWithConnection
import spaceEngineers.controller.extensions.typedFocusedScreen
import spaceEngineers.model.*
import spaceEngineers.model.BootsColour
import spaceEngineers.model.CharacterStats
import spaceEngineers.model.DefinitionId
import spaceEngineers.model.GasContainerObject
import spaceEngineers.model.HandTool
import spaceEngineers.model.ScreenName
import spaceEngineers.model.Vec3F
import spaceEngineers.model.extensions.allBlocks
import testhelp.*
import spaceEngineers.movement.FrameSnapshot
import spaceEngineers.movement.InputSnapshot
import spaceEngineers.movement.KeyboardSnapshot
import testhelp.DEFAULT_ORIENTATION_TOLERANCE
import testhelp.DEFAULT_POSITION_TOLERANCE
import testhelp.DEFAULT_SPEED_TOLERANCE
import testhelp.DEFAULT_SPEED_TOLERANCE_OBSERVER
import testhelp.assertGreaterThan
import testhelp.assertLessThan
import testhelp.assertSameDirection
import testhelp.assertVecEquals
import java.lang.Thread.sleep
import kotlin.test.*
import kotlin.test.assertEquals
import kotlin.test.assertFalse
import kotlin.test.assertNotEquals
import kotlin.test.assertNotNull
import kotlin.test.assertNull
import kotlin.test.assertTrue
import kotlin.time.Duration.Companion.milliseconds


class CharacterAsserts(connectionManager: ConnectionManager) : AbstractMultiplayerSteps(connectionManager) {
Expand Down Expand Up @@ -247,6 +271,16 @@ class CharacterAsserts(connectionManager: ConnectionManager) : AbstractMultiplay
}
}

@Then("Character begins to fall.")
fun character_begins_to_fall() {
mainClient {
repeatUntilSuccess {
val movement = observer.observe().movement
assertTrue(movement.isFalling || movement.isJumping, movement.toString())
}
}
}

@Then("Character begins to fall towards the ground.")
fun character_begins_to_fall_towards_the_ground() {
val gravity = mainClient {
Expand Down Expand Up @@ -480,7 +514,7 @@ class CharacterAsserts(connectionManager: ConnectionManager) : AbstractMultiplay
repeatUntilSuccess {
assertEquals(
0f,
observer.observe().suitEnergy,
observer.observe().energy,
absoluteTolerance = 0.001f,
"Energy was supposed to be depleted."
)
Expand Down Expand Up @@ -578,4 +612,130 @@ class CharacterAsserts(connectionManager: ConnectionManager) : AbstractMultiplay
)
}
}

@Then("Character stats are:")
fun character_stats_are_changed_to(dt: DataTable) {
val dataTable = dt.asMaps().first().map { it.key to it.value.toFloat() }.toMap()
val relativeTolerance = dataTable["relative_tolerance"] ?: 0.001f
println(dataTable)
mainClient {
val observation = observer.observe() as CharacterStats
checkStats(dataTable, observation, relativeTolerance)
checkStats(dataTable, screens.gamePlay.data().hud.statsWrapper, relativeTolerance)
}
}

private fun checkStats(dataTable: Map<String, Float>, stats: CharacterStats, relativeTolerance: Float) {
checkStat(dataTable, "health", stats.health, relativeTolerance)
checkStat(dataTable, "oxygen", stats.oxygen, relativeTolerance)
checkStat(dataTable, "energy", stats.energy, relativeTolerance)
checkStat(dataTable, "hydrogen", stats.hydrogen, relativeTolerance)
}

private fun checkStat(
dataTable: Map<String, Float>,
name: String,
stat: Float,
relativeTolerance: Float
) {
dataTable[name]?.let { tableStat ->
assertEquals(tableStat / 100f, stat, absoluteTolerance = stat * relativeTolerance)
}
}


@Then("hydrogen is less than maximum.")
fun hydrogen_is_less_than_maximum() {
mainClient {
assertLessThan(observer.observe().hydrogen, 1f)
}
}

@Then("health is less than maximum.")
fun health_is_less_than_maximum() {
mainClient {
assertLessThan(observer.observe().health, 1f)
}
}

@Then("oxygen is less than maximum.")
fun oxygen_is_less_than_maximum() {
mainClient {
assertLessThan(observer.observe().oxygen, 1f)
}
}

@Then("Content of hydrogen in the {definitionId} in the inventory is less than maximum.")
fun of_hydrogen_in_the_in_the_inventory_is_less_than_maximum(definitionId: DefinitionId) {
mainClient {
val items = observer.observe().inventory.items
items.filterIsInstance<GasContainerObject>().apply {
assertTrue(
isNotEmpty(),
"No item of type $definitionId found in the inventory, found only ${items.map { it.id }}"
)
}.forEach {
assertLessThan(it.gasLevel, 1f)
}
}
}

@Then("Personal light is off.")
fun personal_light_is_off() = mainClient {
println(screens.gamePlay.data().hud.stats)
assertEquals(0f, observer.observe().currentLightPower)
//assertFalse(observer.observe().lightEnabled, "light is supposed to be off!")
//TODO: check on hud too
}

@Then("Character is dead.")
fun character_is_dead() = mainClient {
with(observer.observe()) {
assertTrue(movement.isDead)
assertEquals(0f, health)
}
}

@Then("Remote terminal for grid {string} is disabled.")
fun remote_terminal_is_disabled(grid: String) = mainClient {
delay(200.milliseconds)
input.startPlaying(
listOf(
FrameSnapshot(
InputSnapshot(
keyboard = KeyboardSnapshot(pressedKeys = listOf(16, 75), text = listOf(' '))
)
)
)
)
delay(200.milliseconds)
val grids = screens.terminal.remoteAccess.data().grids
assertTrue(grids.isNotEmpty(), "No grids to see!")
assertFalse(
grids.firstOrNull() { it.name == grid }?.isSelectable
?: error("No grid with name $grid found, found only ${grids.map { it.name }}"),
"Grid $grid is Selectable and therefore not disabled"
)
}

@Then("Remote terminal for grid {string} is enabled.")
fun remote_terminal_is_enabled(grid: String) = mainClient {
delay(200.milliseconds)
input.startPlaying(
listOf(
FrameSnapshot(
InputSnapshot(
keyboard = KeyboardSnapshot(pressedKeys = listOf(16, 75), text = listOf(' '))
)
)
)
)
delay(200.milliseconds)
val grids = screens.terminal.remoteAccess.data().grids
assertTrue(grids.isNotEmpty(), "No grids to see!")
assertTrue(
grids.first { it.name == grid }.isSelectable,
"Grid $grid is not Selectable and therefore disabled"
)
}
}
49 changes: 37 additions & 12 deletions CucumberTester/src/main/kotlin/bdd/DebugAsserts.kt
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package bdd

import bdd.connection.ConnectionManager
import bdd.repetitiveassert.repeatUntilSuccess
import io.cucumber.java.PendingException
import io.cucumber.java.en.Then
import bdd.connection.ConnectionManager
import spaceEngineers.model.Sound
import kotlin.test.assertTrue


Expand All @@ -11,17 +13,27 @@ class DebugAsserts(connectionManager: ConnectionManager) : AbstractMultiplayerSt
@Then("Sound {string} is being played.")
fun sound_is_being_played(soundNames: String) = mainClient {
repeatUntilSuccess {
val playingSounds = debug.sounds()
soundNames.split(",").map { it.trim() }.forEach { soundName ->
assertTrue(
playingSounds.sound.filter {
it.isPlaying
}.any { it.cueEnum == soundName },
"Playing sound '$soundName' not found, current playing sounds are: ${
playingSounds.sound.filter { it.isPlaying }.map { it.cueEnum }.toSet()
}"
)
}
checkSoundsAreBeingPlayed(soundNames, debug.sounds().sound)
}
}

@Then("Hud sound {string} is being played.")
fun hud_sound_is_being_played(soundNames: String) = mainClient {
repeatUntilSuccess(repeats = 15) {
checkSoundsAreBeingPlayed(soundNames, debug.sounds().hud)
}
}

fun checkSoundsAreBeingPlayed(soundNames: String, sounds: List<Sound>) {
soundNames.split(",").map { it.trim() }.forEach { soundName ->
assertTrue(
sounds.filter {
it.isPlaying
}.any { it.cueEnum == soundName },
"Playing sound '$soundName' not found, current playing sounds are: ${
sounds.filter { it.isPlaying }.map { it.cueEnum }.toSet()
}"
)
}
}

Expand Down Expand Up @@ -66,4 +78,17 @@ class DebugAsserts(connectionManager: ConnectionManager) : AbstractMultiplayerSt
}
}
}

@Then("Text notification {string} appears on HUD.")
fun text_notification_appears_on_hud(text: String) {
mainClient {
repeatUntilSuccess {
val notifications = screens.gamePlay.data().hud.notifications
assertTrue(notifications.any {
it.text == text
}, "No notification with text $text found, only ${notifications.map { it.text }}")
}
println(screens.gamePlay.data().hud.notifications)
}
}
}
12 changes: 7 additions & 5 deletions CucumberTester/src/main/kotlin/bdd/setup/Extensions.kt
Original file line number Diff line number Diff line change
Expand Up @@ -51,15 +51,17 @@ suspend fun SpaceEngineers.ensureCamera(cameraConfig: CameraConfig) {
}
}

suspend fun ConnectionManagerUser.handleScenarioParameter(key: String, value: String) =
suspend fun ConnectionManagerUser.handleScenarioParameter(key: String, value: String) {
when (key) {
"delay_after_spawn" -> delay((value.toFloat() * 1000f).toLong())
"energy" -> admin { admin.character.updateEnergy(energy = value.toFloat()) }
"hydrogen" -> admin { admin.character.updateHydrogen(hydrogen = value.toFloat()) }
"oxygen" -> admin { admin.character.updateOxygen(oxygen = value.toFloat()) }
"energy" -> admin { admin.character.updateEnergy(energy = value.toFloat() / 100f) }
"hydrogen" -> admin { admin.character.updateHydrogen(hydrogen = value.toFloat() / 100f) }
"health" -> admin { admin.character.updateHealth(health = value.toFloat() / 100f) }
"oxygen" -> admin { admin.character.updateOxygen(oxygen = value.toFloat() / 100f) }
"camera" -> mainClient { ensureCamera(CameraConfig.fromText(value)) }
else -> println("Warning, unknown settings: $key - $value")
else -> error("Warning, unknown settings: $key - $value")
}
}

suspend fun ConnectionManagerUser.handleScenarioParameters(data: Map<String, String>) {
val alreadyHandledParameters = setOf("faction", "scenario", "main_client_medbay", "observer_medbay")
Expand Down
2 changes: 1 addition & 1 deletion CucumberTester/src/main/kotlin/testhelp/Assert.kt
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ fun assertCharacterObservationEquals(co1: CharacterObservation, co2: CharacterOb
assertEquals(co1.health, co2.health)
assertEquals(co1.oxygen, co2.oxygen)
assertEquals(co1.hydrogen, co2.hydrogen)
assertEquals(co1.suitEnergy, co2.suitEnergy)
assertEquals(co1.energy, co2.energy)
//assertEquals(co1.camera, co2.camera)
assertEquals(co1.headLocalXAngle, co2.headLocalXAngle)
assertEquals(co1.headLocalYAngle, co2.headLocalYAngle)
Expand Down
Loading

0 comments on commit 925992e

Please sign in to comment.