NRF SDK 0.9

Reading and acting

Connect trains, lines and tags

Read the game’s lines and distinguish their declared tags from tags inherited from parents.

Request the catalogue you need

This guide builds on train queries. Request includeLines to display a line; request includeTags for its tags, which already includes lines. A train may have a lineId even when the catalogue was not requested: a missing join does not mean that the train has no line.

InformationNativeJVM
Train’s line identitytrain.service?.line?.lineIdrecord.service?.line
Look up the linesnapshot.line(lineId)snapshot.line(lineId)
Observed parentline.parentLineIdline.parentId
Depotline.isDepotline.type == LineType.Depot

LineType distinguishes Depot and Other. Other means neither “passenger” nor “freight”. Name is a presentation property; keep LineId as the key even after renaming. A Line record exposes neither commercial frequency nor a calculated list of upcoming departures.

Read explicitly declared tags

Tag associates a TagId with a label. Line.declaredTags describes only tags on that line. A supplied empty list means no local declaration; null means the declaration was not supplied. To test membership, compare identities rather than a name that may change.

Resolve inheritance without hiding unknowns

snapshot.tagsForLine(lineId) combines tags from the line and its parents without duplicates. Use line.declaredTags for local tags only. These reads operate on the copied batch; they do not silently reread the game to complete an incomplete catalogue.

CaseInterpretation
parentInformationAvailable = falseParent relationship unknown, even if parentId is null.
Parent available and nullObserved root: no parent declared.
Parent missing from catalogue, cycle or limit reachedIncomplete resolution: the result remains null.
Non-null empty resultNo tags in the requested resolved chain.

Keep membership three-valued: true, false or null. Reducing null to false would turn an incomplete read into a definite absence of a tag, potentially reversing a mod rule.

Compare local and inherited tags

Native: run with the callback context
package wiki.trainlines

import nimby.*

data class LineTags(
    val line: Line,
    val declared: List<Tag>?,
    val includingParents: List<Tag>?,
)

fun readLineTags(context: ToolContext, id: LineId): LineTags? {
    val snapshot = context.trains(TrainQuery(
        includeService = false,
        includeLocations = false,
        includeTags = true,
    ))
    val line = snapshot.line(id) ?: return null
    return LineTags(line, line.declaredTags, snapshot.tagsForLine(id))
}

// Three-state result: true, false or unknown membership.
fun hasTag(tags: List<Tag>?, id: TagId): Boolean? =
    tags?.any { it.id == id }
JVM: read the catalogue in one capture
package wiki.jvmtrainlines

import fr.nimby.sdk.*

data class LineTags(
    val line: Line,
    val declared: List<Tag>?,
    val includingParents: List<Tag>?,
)

fun readLineTags(game: Game, id: LineId): LineTags? {
    val snapshot = game.trains.snapshot(query = TrainQuery(
        includeService = false,
        includeLocations = false,
        includeTags = true,
    ))
    val line = snapshot.line(id) ?: return null
    return LineTags(line, line.declaredTags, snapshot.tagsForLine(id))
}

// A translated or renamed label does not replace the tag identity.
fun hasTag(tags: List<Tag>?, id: TagId): Boolean? =
    tags?.any { it.id == id }

The card returns the line, its local declarations and the resolved set. Call hasTag with the TagId selected in your configuration. If the result is null, the screen can explain “tags unavailable” and the business rule can explicitly apply its unknown-data behaviour.