Database & Storage
SQLite and MySQL from a gamemode, sync and async.
SQLite
knight
system::start() {
let db = sqlite_open("data/accounts.db");
sqlite_exec(db, "CREATE TABLE IF NOT EXISTS accounts (name TEXT PRIMARY KEY, score INTEGER)");
};
player::command("/save", int score) {
let db = sqlite_open("data/accounts.db");
sqlite_exec(db, "INSERT OR REPLACE INTO accounts VALUES (?, ?)", PlayerName(playerid), score);
};
player::command("/load") {
let db = sqlite_open("data/accounts.db");
let idx = sqlite_query(db, "SELECT score FROM accounts WHERE name = ?", PlayerName(playerid));
if (idx != null) {
SendClientMessage(playerid, "score = {cache_get_value_name_int(idx, 0, "score")}");
}
};
Async queries
For slow queries, use the async variant and a named callback. It runs off the tick loop.
knight
function onScore(result, err) {
if (err == "") {
Log("rows = " + str(cache_get_row_count(result)));
}
}
player::command("/load") {
let db = sqlite_open("data/accounts.db");
sqlite_query_async(db, "onScore", "SELECT score FROM accounts");
};
Passwords
knight
let hash = hash_password(password);
if (verify_password(input, hash)) {
SendClientMessage(playerid, "Logged in.");
}
Warning
Always use
? placeholders for user input. Never build SQL by concatenating strings.Which database?
| Backend | Best for | Details |
|---|---|---|
| SQLite | Single server, small/medium data | SQLite guide |
| MySQL | External database, multiple servers, large data | MySQL guide |