-
Notifications
You must be signed in to change notification settings - Fork 0
Storing Game Data
Beginners often store the wrong type for game data — text where a number belongs, the wrong precision for coordinates, etc. This page shows how to store the common things an open.mp gamemode tracks.
| Game thing | MySQL column | Why |
|---|---|---|
| money, score, ammo | INT |
whole numbers |
| big counters (xp totals) | BIGINT |
won't overflow at billions |
| position x/y/z, angle | FLOAT |
decimals; FLOAT is plenty for SA coords |
| health, armour | FLOAT |
0.0–100.0 |
| skin, interior, world, weapon id |
INT (often SMALLINT) |
small whole numbers |
| color | INT UNSIGNED |
RGBA packed into one number |
| is_banned, is_vip |
TINYINT (0/1) |
booleans |
| player name | VARCHAR(24) |
open.mp names ≤ 24 chars |
| IP address | VARCHAR(45) |
fits IPv4 and IPv6 |
| password hash | VARCHAR(255) |
Argon2 hashes ~100 chars |
| a description / note | TEXT |
long, variable text |
| created / last_login |
DATETIME or TIMESTAMP
|
a moment in time |
Store each component as a FLOAT:
x FLOAT, y FLOAT, z FLOAT, angle FLOATnew Float:x, Float:y, Float:z, Float:a;
GetPlayerPos(playerid, x, y, z);
GetPlayerFacingAngle(playerid, a);
// bind with mysql_stmt_set_float(st, i, x); ...Read back with mysql_rs_get_float_by(0, "x", x). FLOAT is accurate enough for San
Andreas; use DOUBLE only if you truly need more precision.
open.mp colors are a single 32-bit RGBA value. Store as one integer:
color INT UNSIGNEDnew color = GetPlayerColor(playerid); // e.g. 0xRRGGBBAA
mysql_stmt_set_int(st, i, color);
// SetPlayerColor(playerid, savedColor);Use
INT UNSIGNEDso the high bit doesn't make it negative.
MySQL has no real boolean — use TINYINT with 0/1:
banned TINYINT NOT NULL DEFAULT 0,
vip TINYINT NOT NULL DEFAULT 0mysql_stmt_set_int(st, i, isBanned ? 1 : 0);
// reading:
new tmp; mysql_rs_get_int_by(0, "banned", tmp);
new bool:banned = (tmp != 0);Store as text — VARCHAR(45) covers IPv6 too:
new ip[45];
GetPlayerIp(playerid, ip, sizeof ip);
mysql_stmt_set_string(st, i, ip);Let MySQL stamp the time so it's consistent regardless of the server's clock code:
created DATETIME DEFAULT CURRENT_TIMESTAMP,
last_login DATETIME-- update last_login on each login:
UPDATE accounts SET last_login = NOW() WHERE id = ?;Read a datetime back as a string ("2025-01-01 12:00:00"); see
Date & time.
Don't make 13 weapon columns on accounts. Use a child table (one row per item):
CREATE TABLE account_weapons (
account_id INT NOT NULL,
slot TINYINT NOT NULL,
weapon INT NOT NULL,
ammo INT NOT NULL,
PRIMARY KEY (account_id, slot)
) CHARACTER SET utf8mb4;This is a one-to-many relationship — see Designing your tables. The mysql-admin demo uses exactly this pattern.
Always create tables with CHARACTER SET utf8mb4 so names/text in any language store
without being corrupted or rejected by the database. Size VARCHAR to the real
maximum (VARCHAR(24) for names).
Note:
utf8mb4is about safe storage, not display. SA:MP / open.mp chat uses the GTA SA bitmap font, which is single-byte (Windows-1252-style) — it cannot render emoji or most non-Latin characters in-game. So a name might store fine in MySQL but show as boxes/garbage in chat. Still useutf8mb4(it never hurts and avoids data corruption); just don't expect emoji to appear in the game.
- ❌ Store numbers as
VARCHAR("500") — you can'tSUM/ORDER BYthem properly. - ❌ Store a position as one
"x,y,z"string — you can't query/compare it. - ❌ Use
utf8(without mb4) — it can't store all characters (4-byte ones break it). - ❌ Store booleans as
"true"/"false"text — useTINYINT0/1.
Next: Designing your tables · Date & time
Understand
Use
- Installing MySQL
- Docker Compose
- Getting started
- Configuration
- SQL crash course
- Designing your tables
- Storing game data
- Dates & times
- First queries
- Async patterns
- Reading results
- Prepared statements
- Passwords & hashing
- Transactions
- Models (active-record)
- Tutorial: login system
- mysql-admin demo
Deeper
Reference