Skip to documentation
SLOP

tiny.game.dev

Reference tiny.game dev

Defined in tiny.game.

A parser for the commands that drive a headless game: advance some steps, report status, or quit.

API (4)

Actions

Public operations.

Types and contracts

Public types and contracts.

No direct callersNo direct callstiny.gamedev
Static calls · unresolved targets: unknown · external targets: unknown.

Source

Called byCallsdevparsedevvalidateStepCountdevcommon
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallstest; no linkfun.game.src.devtest: headless protocol advances only...devcommondevparse
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsNo direct callsdevcommondevvalidateStepCount
Static calls · unresolved targets: 0 · external targets: 0.

Source: fun/game/src/dev.zig

zig
//! A parser for the commands that drive a headless game: advance some steps, report status, or//! quit.//!//! A tool or test drives the game one command at a time and waits as long as it likes between//! commands, so the game advances only when a command asks it to. A host keeps commands of its own//! beside the shared ones.//!//! A line from an outside tool can name any command and any count, so the host bounds the step//! count and separates the commands it knows from all others.//!//! Each command is one JSON object on its own line, with its name in a `cmd` field and, for a step//! command, a step count in a `frames` field that is 1 when the line leaves it out. The `frames`//! field counts simulation steps. `common` maps a name and a count to a `Command`, and it returns//! `null` for a name outside the three, so a host can try its own commands next. `parse` reads a//! whole line and returns `error.UnknownCommand` for a name outside the three. A step count runs//! from 1 to a maximum the caller passes, and both functions return `error.StepCountOutOfRange` for//! any other count.const std = @import("std");/// One of the three commands every headless host understands. A host switches on it to decide/// whether to advance, report or stop.pub const Command = union(enum) {    /// Advance the simulation by the given number of steps, from 1 to the caller's maximum.    step: u32,    /// Report the host's state. A host leaves the simulation at the step it had reached for this    /// command.    status,    /// Stop serving commands.    quit,};/// Checks that a step count lies between 1 and `max_steps`. `common` checks the count of each step/// command with it. The call returns `error.StepCountOutOfRange` for a count of zero or above/// `max_steps`, so a `max_steps` of zero refuses every count. `frames` is a count of simulation/// steps.pub fn validateStepCount(frames: u32, max_steps: u32) error{StepCountOutOfRange}!void {    if (frames == 0 or frames > max_steps) return error.StepCountOutOfRange;}/// Maps a command name and a step count to a `Command`, or returns `null` for a name other than/// `step`, `status` or `quit`. A host that has commands of its own calls it first and handles a/// `null` result with its own names. The call checks the count for `step` alone, and returns/// `error.StepCountOutOfRange` for a count of zero or above `max_steps`. Names match byte for byte,/// case included.pub fn common(name: []const u8, frames: u32, max_steps: u32) error{StepCountOutOfRange}!?Command {    if (std.mem.eql(u8, name, "step")) {        try validateStepCount(frames, max_steps);        return .{ .step = frames };    }    if (std.mem.eql(u8, name, "status")) return .status;    if (std.mem.eql(u8, name, "quit")) return .quit;    return null;}const Raw = struct { cmd: []const u8, frames: u32 = 1 };/// Parses one line holding a JSON object into a `Command`. A host that understands only the three/// shared commands parses each line with it. The object names its command in `cmd` and its step/// count in `frames`, which is 1 when the line leaves it out, and the parser skips any other field./// The call returns `error.UnknownCommand` for a name outside the three, checks the count for/// `step` alone, and returns `error.StepCountOutOfRange` for a count of zero or above `max_steps`./// The call returns the errors of `std.json.parseFromSliceLeaky` for a line that is malformed JSON,/// a line whose JSON value is an array, a string, a number, a Boolean or null, a line that repeats/// a field, a line that lacks `cmd`, or a line that holds a field of the wrong type, such as a/// `cmd` that is a number or a `frames` that is negative, fractional or above the `u32` range. A/// `frames` written as a string of digits, such as `"3"`, parses as that number. The parsed strings/// live in `arena`, and the call frees nothing, so the caller resets or frees the arena.pub fn parse(arena: std.mem.Allocator, line: []const u8, max_steps: u32) !Command {    const raw = try std.json.parseFromSliceLeaky(Raw, arena, line, .{ .ignore_unknown_fields = true });    return (try common(raw.cmd, raw.frames, max_steps)) orelse return error.UnknownCommand;}test "headless protocol advances only on step commands" {    var arena_state = std.heap.ArenaAllocator.init(std.testing.allocator);    defer arena_state.deinit();    const arena = arena_state.allocator();    var clock = try @import("clock.zig").Clock.init(.{ .steps_per_second = 60, .source_frames_per_second = 20 });    for ([_][]const u8{ "{\"cmd\":\"status\"}", "{\"cmd\":\"step\",\"frames\":3}", "{\"cmd\":\"status\"}" }) |line| {        const command = try parse(arena, line, 8);        switch (command) {            .step => |count| {                for (0..count) |_| _ = clock.commandStep();            },            else => {},        }    }    try std.testing.expectEqual(@as(u64, 3), clock.index);}

Source: fun/game/src/root.zig:118

zig
pub const dev = @import("dev.zig");

Audit

Definitions5
Public names5
Members3
Version26.7.0
Revisiondaab053ee433