Skip to content

osrlib.crawl.views

The projection API: the player's safe whitelist and the referee's full state.

A view is the snapshot a front end renders: everything on the screen after a command, in one frozen object.

Where the views sit. A command changes the session state that GameSession keeps, and build_player_view and build_referee_view read that state to build these projections. The player view is built from session state alone and never from the event log; the referee view has one typed field per group the save keeps, so it includes the event log along with everything else, each group as the session's own model. GameSession.view is the entry point most games call, with a Visibility to pick which one. Events tell you what just happened, and a view tells you what is true now. The ids a view includes, MemberView.id and EncounterGroupView.id, are the ids the commands in osrlib.crawl.commands name.

The player view is an enumerated whitelist: party public sheets, location and facing, the mapped cells with their edges (walked cells, the remembered cells the party's light has shown it, and what its light reveals right now, with secret doors rendered as wall until discovered), known piles and emptied caches in explored space, active effects on party members with their remaining durations, the elapsed clock, the mode, the journal, the active quests with their revealed objectives, the current encounter or battle's public state, fatigue, exhaustion, and deprivation status, and the adventure's public prose.

It never includes unexplored geometry, undiscovered traps or secret doors, monster hit points or stat internals, referee-visibility roll outcomes, session flags, trigger fired-marks, referee notes, quest wiring such as activation clauses, patterns, conditions, rewards, and hidden objectives, the quests that are not active, meaning both the ones nobody has taken on yet and the ones already finished, RNG state, or the master seed, which lives only in the save and reaches neither view.

The referee view includes everything else the save does, minus RNG internals and the seed, for LLM referees and tests. Its fields are the groups session_state writes, so view.monsters[0].current_hp and view.flags["key"] read with the types this reference documents, and view.model_dump(mode="json") is that save payload without the two withheld keys. Never trust the client with it: a networked game keeps the session and the referee view on the server and sends only the player view, or player-visibility events, over the wire. The guide Views and visibility walks the whole projection in a running front end.

EdgeView

Bases: BaseModel

One visible edge: what occupies it, and a door's state.

You get these from the edges of an ExploredLevelView, keyed by canonical edge key. An undiscovered secret door renders as wall, so a front end that draws what it is given never reveals one.

kind instance-attribute

kind: str

What occupies the edge: "open", "wall", or "door", the wire values of EdgeKind. An undiscovered secret door reports "wall".

door_open class-attribute instance-attribute

door_open: bool | None = None

Whether the door stands open. None on an edge that is not a door.

door_wedged class-attribute instance-attribute

door_wedged: bool | None = None

Whether the door has been wedged with an iron spike. None on an edge that is not a door.

EncounterGroupView

Bases: BaseModel

A monster group as the players see it: what it is, how many, how far, how it looks.

You get these from EncounterView.groups. Hit points and stat internals never appear, because the players work from what they can see across the room.

id instance-attribute

id: str

The group's id, which is the command vocabulary: a battle declaration names its target_group_id with it, so a wire client needs it to fight at all. It is an allocator ordinal rather than a secret, the same way a MemberView.id is.

label instance-attribute

label: str

What the group is called, such as "goblins", for the line a front end prints.

count instance-attribute

count: int

How many of the group are still standing. The dead are not counted.

distance_feet instance-attribute

distance_feet: int

How far away the group is on the range track, in feet.

visible_conditions instance-attribute

visible_conditions: tuple[str, ...]

The conditions visible on the living members of the group, as Condition wire values, sorted and deduplicated so the same condition on six goblins reads once.

EncounterView

Bases: BaseModel

The current encounter or battle's public state.

You get one from PlayerView.encounter, and None there means nothing is happening.

Four id tuples, declarers, front_rank, immobile, and reloading, describe the round's shape as the players know it at the table: who is able to act, who stands close enough to swing, who is held fast, and who is still cranking a windlass. Each one corresponds to a rejection the engine would otherwise raise against the whole round, so a front end that reads all four offers only the declarations the engine will accept. Without them a front end has to assume a rank width, and a wrong assumption costs the party its turn.

groups instance-attribute

groups: tuple[EncounterGroupView, ...]

The monster groups in the encounter, in the order the encounter holds them.

stance instance-attribute

stance: str | None

How the monsters are behaving, as a ReactionResult wire value: "attacks", "hostile", "uncertain", "indifferent", or "friendly". None before the reaction roll has settled it.

in_battle instance-attribute

in_battle: bool

Whether the encounter has become a battle with rounds and declarations.

battle_round class-attribute instance-attribute

battle_round: int | None = None

The current battle round, counting from the first. None outside a battle.

pursuit_gap_feet class-attribute instance-attribute

pursuit_gap_feet: int | None = None

How far ahead of its pursuers the fleeing party is, in feet. None when nobody is pursuing.

declarers class-attribute instance-attribute

declarers: tuple[str, ...] = ()

Every member who has to declare this round, in marching order: the ones living and able to act. A ResolveBattleRound naming any other roster, a slept or paralysed member included, is rejected whole with battle.declaration.roster_mismatch.

front_rank class-attribute instance-attribute

front_rank: tuple[str, ...] = ()

The living members close enough to attack in melee, in marching order. That is the party's first rank at the current formation width, or every living member when the ruleset's formation_width_limit flag is off. A melee attack declared for anyone else is rejected with battle.declaration.not_in_front_rank, and inside melee reach a weapon that is both melee and missile counts as a melee weapon.

immobile class-attribute instance-attribute

immobile: tuple[str, ...] = ()

The declarers who cannot move this round, which in practice means the entangled, since the states that stop a move otherwise stop a declaration as well. A move declaration of any kind from one of them is rejected with battle.declaration.cannot_move.

reloading class-attribute instance-attribute

reloading: tuple[str, ...] = ()

The members who may not fire a reload weapon this round, because they fired one last round (combat.attack.reload). Empty when the ruleset's weapon_reload flag is off, so a front end can combine this list with the weapon's own qualities and never read the flag itself.

ExplorationCounters

Bases: BaseModel

The crawl bookkeeping a session keeps between commands: distance, rest, wandering, noise, sleep, supplies.

You get one from RefereeView.exploration. These are the counters GameSession keeps as attributes of its own and a save writes under its exploration key, gathered here under the names the session gives them. They are the referee's bookkeeping and none of them reaches PlayerView, which reports the party's fatigue, exhaustion, and deprivation as status rather than as the counts behind it.

odometer_thirds instance-attribute

odometer_thirds: int

How much of the current turn the party's steps have used up, in thirds of its movement rate. A full turn's worth advances the clock and resets this to zero.

turns_since_rest instance-attribute

turns_since_rest: int

Turns since the party last rested, which is what the fatigue cadence counts. A Rest resets it.

wandering_counter instance-attribute

wandering_counter: int

Turns since the last wandering-monster check. Reaching the level's interval fires the check and resets this to zero.

noise_since_check instance-attribute

noise_since_check: bool

Whether the party has made noise since the last wandering check, which any attempt to force a door does, whether or not the door opens. Noise raises the next check's chance by one and then clears.

sleep_count instance-attribute

sleep_count: int

How many nights or days the party has slept through. Preparing spells needs a sleep the caster has not already prepared from.

last_prepared_sleep instance-attribute

last_prepared_sleep: dict[str, int]

The sleep_count at which each caster last prepared spells, keyed by character id. It is what enforces one preparation per sleep.

alerted_areas instance-attribute

alerted_areas: tuple[str, ...]

The keyed areas whose occupants have been alerted, as area references. Monsters that heard the party coming are not surprised when it walks in.

heard_areas instance-attribute

heard_areas: tuple[str, ...]

The keyed areas the party has heard something in, as area references. A party that knows what stands behind the door is not surprised by it.

provisions_day instance-attribute

provisions_day: int

The last whole game day whose food and water upkeep has been settled, counting from the start of the session. Each day boundary charges the party once and then raises this.

ExploredLevelView

Bases: BaseModel

One level's explored map: the cells the party knows, and the edges around them.

You get these from PlayerView.explored, one per level the party has any knowledge of. This is the map to draw: nothing outside it is knowledge the party has.

dungeon_id instance-attribute

dungeon_id: str

The id of the dungeon this level belongs to.

level_number instance-attribute

level_number: int

The 1-based level number.

cells instance-attribute

cells: tuple[Position, ...]

The known cells as (x, y) pairs: the cells the party has walked, then the cells it remembers having seen, then the cells its light shows from where it stands right now. Lighting a torch redraws the room in the next view, with no footstep in between.

edges instance-attribute

edges: dict[str, EdgeView]

The edges around those cells, keyed by the canonical edge key that edge_key returns, in the form "{x},{y}:north" or "{x},{y}:west". Each physical edge appears once, so a wall between two known cells is one entry, not two.

MemberEffectView

Bases: BaseModel

An active effect on a party member: the players track their own torches and spells.

You get these from PlayerView.effects. Only effects attached to a party member appear. An effect anchored to a dungeon cell is the referee's business and stays out.

character_id instance-attribute

character_id: str

The id of the member the effect is attached to, matching a MemberView.id.

kind instance-attribute

kind: str

The effect kind, such as "light" or "fatigue", which is the same string an EffectActiveCondition names.

remaining_rounds instance-attribute

remaining_rounds: int | None

Rounds left before the effect expires, never below zero. None means the players are not told: an effect with no expiry, and any effect a potion granted, because the referee rolls and tracks a potion's duration and never announces it.

MemberView

Bases: BaseModel

One member's public sheet: the players know their own characters.

You get these from PlayerView.party, in marching order, and every party member has one, living or dead. A member's own numbers are not secrets, so the sheet is full, and the one thing play hides from the players is the identity of an unidentified magic item in the pack.

Examples:

from osrlib.crawl.views import MemberView

sheet = MemberView(
    id="pc1",
    name="Hild",
    class_id="fighter",
    level=1,
    current_hp=7,
    max_hp=7,
    conditions=(),
    inventory={},
    memorized_spells=(),
)
assert sheet.id == "pc1"  # the id a command's character_id names

id instance-attribute

id: str

The member's character id. This is the id you put in the character_id of a command such as GrantItem or a battle declaration, so a wire client can act without holding the session.

name instance-attribute

name: str

The character's name, as the player wrote it.

class_id instance-attribute

class_id: str

The character class id, such as "fighter", from the class catalog.

level instance-attribute

level: int

The character's experience level.

current_hp instance-attribute

current_hp: int

Current hit points. Zero or less means the member is down, and conditions says what took them out.

max_hp instance-attribute

max_hp: int

Maximum hit points at the current level.

conditions instance-attribute

conditions: tuple[str, ...]

The conditions on the member right now, as Condition wire values such as "dead" or "sleeping", in the order the ledger holds them.

inventory instance-attribute

inventory: dict

The member's pack, in the shape the inventory serializes, with the keys items, purse, valuables, worn_armour, shield, wielded, and rings. Magic items are masked until identified: an unidentified one shows a category display name instead of its true name. When that display name was built from a base weapon ("a dagger with a faint aura"), the entry also includes the qualities of that mundane weapon, exactly as an identified one does, so a front end can classify a declaration without being told the arm's bonus, curse, or template id. The missile_ranges key comes with it only for a weapon the rules give ranges to, so read the key as absent on a sword rather than empty. An item whose display comes from its category instead, such as a staff, includes neither field even when it resolves to a weapon, because the display never named that weapon. Charges never appear at any identification level.

memorized_spells instance-attribute

memorized_spells: tuple[dict, ...]

The prepared spells, one dumped MemorizedSpell per copy, in memorization order. Empty for a class that casts nothing.

ObjectiveView

Bases: BaseModel

One revealed objective as the players know it: what it is called, and whether it is done.

You get these from QuestView.objectives. A hidden objective has no view at all: one nobody has been told about is absent from the list rather than listed as unknown, which is why state needs only the two values a visible objective can be in. The authored source is ObjectiveSpec and the live state is ObjectiveState, neither of which a wire client holds.

id instance-attribute

id: str

The objective's authored id, scoped to its quest.

name instance-attribute

name: str

The objective's display label: its authored name, or its id when the document authors none. It is never empty, because the view's job is saying what the objective is called.

state instance-attribute

state: str

"incomplete" or "complete".

PileView

Bases: BaseModel

A known dropped pile in explored space.

You get these from PlayerView.piles, keyed by cell reference. A pile in a cell the party has not walked is left out, so the view never tells the players about loot they have not found.

items instance-attribute

items: tuple[str, ...]

One display string per thing in the pile, in the order mundane items, magic items, then valuables. A mundane entry reads "{item_id}×{quantity}". A magic item shows its name once identified and its masked display name before that. A valuable shows its name, or its kind when it has no name.

coins_gp_value instance-attribute

coins_gp_value: int

The pile's coins, converted to their value in gold pieces.

PlayerView

Bases: BaseModel

The safe projection: an enumerated whitelist of exactly the fields a player may see.

Build one with build_player_view, or with GameSession.view and Visibility.PLAYER. This is the object a networked game sends over the wire: every field on it is safe to show at the table, and nothing the party has not learned is on it. Rebuild it after every command, because it is a frozen snapshot and nothing updates it in place.

adventure_name instance-attribute

adventure_name: str

The adventure's title.

adventure_description instance-attribute

adventure_description: str

The adventure's public prose, the blurb a front end shows on the title screen.

town_name instance-attribute

town_name: str

The base town's name.

town_description instance-attribute

town_description: str

The base town's public prose.

town_services instance-attribute

town_services: tuple[str, ...]

The services the town offers, as authored prose for a front end to list.

party instance-attribute

party: tuple[MemberView, ...]

The party's public sheets, in marching order, the dead included.

location instance-attribute

location: PartyLocation

Where the party is: the town, or a dungeon cell with its facing.

clock_rounds instance-attribute

clock_rounds: int

The elapsed game clock in rounds, counting from the start of the session.

mode instance-attribute

mode: str

The session mode as a SessionMode wire value: "town", "exploring", "encounter", "battle", "game_over", or "victory". It tells a front end which commands are legal right now.

explored instance-attribute

explored: tuple[ExploredLevelView, ...]

The party's map, one entry per level it knows anything about.

piles instance-attribute

piles: dict[str, PileView]

The dropped piles the party knows about, keyed by the cell reference cell_ref returns. A pile in a cell the party has not walked is left out.

emptied_caches instance-attribute

emptied_caches: tuple[str, ...]

The treasure caches the party has already emptied, as "{dungeon}:{level}:{id}" references, so a front end can draw a looted cache as looted.

effects instance-attribute

effects: tuple[MemberEffectView, ...]

The active effects on party members, in ledger order.

fatigued instance-attribute

fatigued: bool

Whether any member is fatigued.

exhausted instance-attribute

exhausted: bool

Whether any member is exhausted.

deprivation instance-attribute

deprivation: dict[str, dict[str, int]]

Food and water deprivation, keyed by character id, each value holding food_days and water_days. A member with no deprivation on either track is left out, so an empty dict means the party has been eating and drinking.

journal instance-attribute

journal: tuple[JournalEntry, ...]

The session journal, shipped as written: the players' own record of the adventure, in order of discovery, each beat with the clock position it landed at. The wiring behind the beats, meaning trigger fired-marks and referee notes, stays out.

quests instance-attribute

quests: tuple[QuestView, ...]

The quests in play, in the order the adventure authored them: active ones only. A quest nobody has taken on yet is not the party's business, and a finished one leaves the list, and its record is the journal, which keeps every beat it wrote.

encounter class-attribute instance-attribute

encounter: EncounterView | None = None

The current encounter or battle's public state, or None when the party is not in one.

QuestView

Bases: BaseModel

One active quest as the players know it: the charge, who gave it, and where it stands.

You get these from PlayerView.quests. The wiring that starts a quest, checks it off, and pays it, meaning its clauses, patterns, conditions, and rewards, never appears: that is the game's secret exactly as a trigger's is. Read the authored quest itself from QuestSpec and its live state from QuestState when you hold the session.

id instance-attribute

id: str

The quest's authored id.

name instance-attribute

name: str

The quest's authored display name.

narrative instance-attribute

narrative: str

The quest's authored offer beat, or the empty string when unauthored. The words themselves travel, because a wire client holds no adventure document to resolve them from.

speaker instance-attribute

speaker: str

Who is speaking the offer, such as "Sister Halda", or the empty string when the block authors no attribution.

objectives instance-attribute

objectives: tuple[ObjectiveView, ...]

The revealed objectives, in the order the quest authored them.

RefereeView

Bases: BaseModel

The full state projection minus RNG internals, one typed field per group the save keeps.

Build one with build_referee_view, or with GameSession.view and Visibility.REFEREE. Use it behind the screen: for the context an LLM referee reasons over, for a debugging panel, for a test that asserts on state a player may not see. Never send it to a player's client, and draw nothing a player sees from it, because that is what PlayerView is for.

Each field is the session's own model rather than a dict, so you read view.monsters[0].current_hp and view.flags["key"] with the types this reference documents, and each field's docstring names the model to read next. The fields are the groups session_state writes, minus the master seed and the RNG stream positions, so view.model_dump(mode="json") is that save payload without those two keys. The seed and the stream positions live only in the save, because knowing them would let a player predict every roll to come.

The view is a snapshot of the moment it was built: the session's mutable state is copied into it, so play going on afterwards leaves the view as it was, and editing what you find on a view changes nothing on the session. Being frozen fixes the view's fields rather than their contents, so rebinding view.flags raises while view.flags["key"] = 1 and view.monsters[0].current_hp = 0 edit the view's own copies and are allowed. Build a fresh view after each command rather than editing one. The command log, the event log, and the journal are shared with the session instead of copied, because a command, an event, and a journal entry are frozen records of something that has already happened.

ruleset instance-attribute

ruleset: Ruleset

The options this session plays under, as a Ruleset: the flags that decide which optional rules are on.

party instance-attribute

party: Party

The party, as a Party of full Character sheets in marching order, the dead included. Every number is here, the spell book and the true names of magic items among them, so render a player's own sheet from PlayerView.party instead, which masks what the party has not identified.

adventure instance-attribute

adventure: Adventure

The whole authored document, as an Adventure: the town, the dungeons with their complete geometry and keyed areas, the triggers, and the quests. It is the map with nothing hidden, so draw the party's map from PlayerView.explored instead. The document is frozen and the view copies it even so, because the tree under it contains dicts a caller can edit in place, the town's travel turns and each level's edges among them.

mode instance-attribute

The SessionMode the session is in, which decides the commands it will accept right now.

clock_rounds instance-attribute

clock_rounds: int

The elapsed game clock in rounds, counting from the start of the session.

allocator instance-attribute

allocator: IdAllocator

The id source, as an IdAllocator: the counter each <kind>-NNNN id is handed out from, which is what makes two runs of the same commands name things identically.

ledger instance-attribute

ledger: EffectsLedger

The live effects, as an EffectsLedger: spells running, conditions, a torch burning down, each with the round it expires at. It contains the effects anchored to dungeon cells as well as the ones on members, and it contains a potion's true duration, which the rules keep from the players.

dungeon_state instance-attribute

dungeon_state: DungeonState

What play has written over the authored map, as a DungeonState: where the party stands, the cells it has walked and seen, door state, found and sprung traps, drop piles, and generated caches.

monsters instance-attribute

monsters: tuple[MonsterInstance, ...]

Every creature spawned this session, as MonsterInstance values in the order they were spawned, the defeated ones included, so a later event can still name what it was. Hit points and stat internals are here, which is the line the player view draws: the party sees only EncounterGroupView.

npcs instance-attribute

npcs: tuple[Character, ...]

The NPC adventurers in play, as Character sheets in the order they joined. They are characters rather than monsters, and they fight by the party's own rules.

flags instance-attribute

flags: dict[str, str | int | bool]

The session flag store, keyed as the game chose: the memory SetFlag writes and an adventure's gates and triggers read. Flags are content wiring, so no flag ever reaches a player view.

fired_triggers instance-attribute

fired_triggers: tuple[str, ...]

The ids of the triggers that have fired, in the order they first fired. It answers "has this fired before", and it is referee-only wiring: the beat a trigger wrote reaches the players through the journal instead.

journal instance-attribute

journal: tuple[JournalEntry, ...]

The adventure's beats, as JournalEntry values in the order they were written. The players read the same list, and PlayerView.journal is where a front end reads it.

quests instance-attribute

quests: dict[str, QuestState]

Every authored quest's live state, as QuestState values keyed by quest id, in the order the adventure authored them: the inactive and completed quests as well as the active ones, and every objective whether revealed or hidden. The players' own reading is PlayerView.quests.

listener_state instance-attribute

listener_state: dict[str, dict]

Each registered listener's state, keyed by its key, in the shape that listener's handle returned. The session stores it and never interprets it, so what the keys mean is the game's business.

death_records instance-attribute

death_records: dict[str, DeathRecord]

When and how each dead party member died, as DeathRecord values keyed by character id. Raise dead reads the day count from here and neutralize poison the round window.

defeated_monsters instance-attribute

defeated_monsters: tuple[DefeatedMonsterRecord, ...]

The creatures defeated since the last experience award, as DefeatedMonsterRecord values in the order they fell. GameSession.award_adventure_xp adds up their xp and clears the list.

deprivation instance-attribute

deprivation: dict[str, DeprivationState]

Each member's food and water counts, as DeprivationState values keyed by character id, one per member a day boundary has charged and the members on zero among them. PlayerView.deprivation reports the same counts for the members going short alone.

treasure_snapshot_cp instance-attribute

treasure_snapshot_cp: int | None

What the party's treasure was worth in copper pieces when it left town, or None when no delve is under way. The adventure award pays for the difference between this and what comes back.

exploration instance-attribute

exploration: ExplorationCounters

The crawl bookkeeping, as ExplorationCounters: distance walked, turns since rest, the wandering cadence, noise, sleep, and provisions.

encounter instance-attribute

encounter: EncounterState | None

The encounter under way, as an EncounterState, or None when nothing is happening. It contains each group's monster ids, its distance, the stance the reaction roll settled, and any chase in progress. The players' reading of the same encounter is PlayerView.encounter.

battle instance-attribute

battle: BattleState | None

The battle under way, as a BattleState, or None outside one. It contains the round number and the per-battle trackers, including who fired a reloading weapon last round.

command_log instance-attribute

command_log: tuple[SerializeAsAny[Command], ...]

Every accepted command, in order, each one the Command subclass it was issued as, so its own fields are there to read. Refused commands are absent, because they changed nothing, and replay_game re-executes this list from the master seed to rebuild the session.

event_log instance-attribute

event_log: tuple[SerializeAsAny[Event] | dict, ...]

Everything that has happened, in order, each entry the Event subclass that was emitted, including the referee-visibility events a player never sees. An entry restored from a save whose event type this library has no class for stays the raw mapping it arrived as, so check for a dict before reading an entry's attributes. The union is what keeps a raw entry raw: an Event instance validates as the event, while a mapping, which a model refuses under strict validation, falls to the dict arm and passes through unchanged.

build_player_view

build_player_view(session) -> PlayerView

Build the player view from session state, never from the event log.

Call it after every accepted command to get the snapshot your front end renders, and send that object rather than the session to any client you do not control. GameSession.view with Visibility.PLAYER calls this for you, so use it when you already hold the session and reach for this function when you want the builder itself.

The call reads session state and mutates nothing, so building a view twice gives two equal snapshots and costs the party no game time.

Parameters:

Name Type Description Default
session GameSession

The running session.

required

Returns:

Type Description
PlayerView

The frozen whitelist projection, holding only what the party has learned.

Examples:

from osrlib.core.alignment import Alignment
from osrlib.core.character import CHARACTER_CREATION_STREAM, create_character
from osrlib.core.rng import RngStreams
from osrlib.core.ruleset import Ruleset
from osrlib.crawl.adventure import Adventure, TownSpec
from osrlib.crawl.dungeon import DungeonSpec, LevelSpec
from osrlib.crawl.party import Party
from osrlib.crawl.session import GameSession
from osrlib.crawl.views import build_player_view

rules = Ruleset()
rng = RngStreams(master_seed=7).get(CHARACTER_CREATION_STREAM)
hero = create_character(
    name="Hild",
    class_id="fighter",
    alignment=Alignment.LAWFUL,
    ruleset=rules,
    stream=rng,
)
level = LevelSpec(number=1, width=1, height=1, entrance=(0, 0))
crypt = DungeonSpec(id="crypt", name="The Old Crypt", levels=(level,))
adventure = Adventure(name="A First Delve", town=TownSpec(name="Threshold"), dungeons=(crypt,))
session = GameSession.new(Party(members=[hero.character]), adventure, seed=7)

player = build_player_view(session)
print(player.mode)
# town
print(player.party[0].id)
# character-0001
assert "flags" not in player.model_dump()  # session flags are the game's secret

build_referee_view

build_referee_view(session) -> RefereeView

Build the referee view: every group the save keeps, typed, minus the seed and the RNG streams.

Use it for the context an LLM referee reasons over, for a debugging panel, or for a test that asserts on state a player may not see. GameSession.view with Visibility.REFEREE calls this for you, so use that when you already hold the session and reach for this function when you want the builder itself. Never hand the result to a player's client: that is what build_player_view is for. To store a session rather than read it, call save_game, which keeps the seed and the stream positions a restored game needs.

The call reads session state and mutates nothing. What it returns is a snapshot rather than a window: the session's mutable models are copied into it, so the session playing on afterwards leaves the view as it was, and editing what you find on the view changes nothing on the session. A frozen model whose own containers cannot be edited goes in as it is, which covers the ruleset, the commands, the events, the journal entries, and the death and defeat records. The adventure is frozen as well and is copied anyway, because the authored tree contains dicts a caller can edit in place, the town's travel turns and each level's edges among them.

Parameters:

Name Type Description Default
session GameSession

The running session.

required

Returns:

Type Description
RefereeView

The frozen full-state projection, minus the master seed and the RNG stream positions.

Examples:

from osrlib.core.alignment import Alignment
from osrlib.core.character import CHARACTER_CREATION_STREAM, create_character
from osrlib.core.rng import RngStreams
from osrlib.core.ruleset import Ruleset
from osrlib.crawl.adventure import Adventure, TownSpec
from osrlib.crawl.commands import SetFlag
from osrlib.crawl.dungeon import DungeonSpec, LevelSpec
from osrlib.crawl.party import Party
from osrlib.crawl.session import GameSession
from osrlib.crawl.views import build_referee_view

rules = Ruleset()
rng = RngStreams(master_seed=7).get(CHARACTER_CREATION_STREAM)
hero = create_character(
    name="Hild",
    class_id="fighter",
    alignment=Alignment.LAWFUL,
    ruleset=rules,
    stream=rng,
)
level = LevelSpec(number=1, width=1, height=1, entrance=(0, 0))
crypt = DungeonSpec(id="crypt", name="The Old Crypt", levels=(level,))
adventure = Adventure(name="A First Delve", town=TownSpec(name="Threshold"), dungeons=(crypt,))
session = GameSession.new(Party(members=[hero.character]), adventure, seed=7)
session.execute(SetFlag(key="gate_raised", value=True))

referee = build_referee_view(session)
print(referee.mode, referee.clock_rounds)
# town 0
print(referee.party.members[0].id, referee.party.members[0].current_hp)
# character-0001 3
print(referee.flags)  # the wiring a player never sees
# {'gate_raised': True}