Database read ​
Once the game database has loaded, you can read a whole typed value or pick out a field whose type you know. To work with rows, look one up by its label or use a cursor to walk a table. You use the same dotted paths as the database operations, hashed with fnv1a64, to identify what to read.
| Header | swofty/db. |
| Namespace | swofty::db |
| Table | SwoftyApi::db (SwoftyDb) |
| Feature | db — stable (shared with the database write operations) |
| API version | 5 |
| Thread | Caller thread |
Check the swofty::db::Result returned by every call: ok, late, unavailable or invalid. The result codes explain each one.
Strings ​
The game stores database text XOR-encoded (GdbStringRecord, key k_Gdb_StringXorKey). From core 0.2.11, string_at, the s of a string get or cell, and row_name return the decoded text: printable UTF-8 of at most 16 KiB, or no string. A record that does not decode gives invalid from string_at and a null s elsewhere. If the core cannot decode on this build (the key or the record layout is missing), string_at returns unavailable. Earlier cores returned the encoded bytes.
The core keeps one decoded copy per record, so a returned pointer normally stays valid for the whole session. That table holds at most 32768 strings (8 MiB); past that, a string's pointer stays valid only until the next db call on the same thread. Copy a string if you keep it.
Calls ​
| Call | Returns |
|---|---|
available() | true once the database has loaded |
get(key, out) / get(hash, out) | whole SwoftyDbValue by dotted key or pre-hashed key |
int_at(key, out) | one int64_t field |
float_at(key, out) | one double field |
string_at(key, out) | one const char * field |
bool_at(key, out) | one int32_t field |
open(table, cursor) | positions a cursor at the first row |
row(table, label, cursor) | positions a cursor at the row whose _metadata_ is label, among rows 0 to _<row>_instancecount_ - 1 |
step(cursor) | advances; late when the table is exhausted |
cell(cursor, field, out) | one field of the cursor's current row |
row_name(cursor) | the current row's label (its _metadata_), or nullptr |
When you read a whole SwoftyDbValue, its tag tells you which of i, f or s holds the value. The tag is a swofty::db::Tag: integer, real, string, enumeration, id or boolean. You own the SwoftyDbCursor, so zero-initialise it before calling open or row.
Example ​
Here's how you read one field, then walk a table to list every row:
#include <swofty/db.hpp>
namespace db = swofty::db;
SWOFTY_ON_LOAD
{
if (!db::available())
return;
int64_t secs = 0;
if (db::int_at("rules.stop_go_penalty.penalty_duration", &secs) == db::Result::ok)
swofty::log("[my-addon] stop-go penalty is %lld s", (long long)secs);
db::Cursor cur{};
for (db::Result r = db::open("tracks", &cur); r == db::Result::ok; r = db::step(&cur))
swofty::log("[my-addon] track %s", db::row_name(&cur));
}
SWOFTY_ADDON()The loop prints the 43 rows of tracks. Name your plugin in operations.native:
"operations": {
"native": [{ "dll": "native/my_plugin.dll" }]
}Look up dotted keys in the game database reference. For a row count, use <container>._<Row>_instancecount_.
Availability ​
The db-read engine lane hasn't landed yet, so every call on current builds returns unavailable. Guard every call with available(). See the native-libraries design.