The server itself: repo now mirrors the machine it runs on, plus install.sh

The repository carried two different servers side by side - the early
`justrp` prototype with its Python auth API, and a snapshot of the real
one under `server-code/`. Only the second one is a server anyone should
start from, so the prototype is gone and the real one moved to the root.

Taken from the live box, so the UI is the finished version (the tokens,
the county-records sheets and the variable fonts landed after the last
snapshot was pushed):

  resources/[rp]/   rp_db, rp_core, rp_session, rp_loading, rp_ui,
                    rp_selftest, rp_dbtest
  bin/              supervise.sh (keep-alive + console FIFO), rcon, init script
  etc/schema.sql    accounts, characters, transactions, inventory, vehicles
  assets/fonts/     the bundled subsets
  docs/SERVER.md    how it is put together, resource by resource

install.sh turns a clean Ubuntu/Debian box into this server in one
command: recommended FXServer build, MariaDB with the schema, resources,
server.cfg + a generated database password, boot entry (systemd or
init.d), then it waits for the Cfx registration. --name/--port/--db-name
let a second server live on the same machine. Tested end to end on a
spare install root: build 25770 fetched, schema applied, boot entry
written, FXServer started and stopped exactly where a wrong licence key
should stop it.

No secrets travel with it: the licence key and the database password live
in data/secrets.cfg on the machine, and .gitignore now names it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Claude Opus 5
2026-08-12 23:23:33 +00:00
co-authored by Claude Opus 5
parent 80c1d75d2f
commit 71856b15e9
66 changed files with 2030 additions and 3814 deletions
+105
View File
@@ -0,0 +1,105 @@
-- ---------------------------------------------------------------------------
-- Los Santos RP - authoritative schema
-- Everything the server considers truth lives here. Nothing gameplay-relevant
-- is stored client-side.
-- ---------------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS accounts (
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
username VARCHAR(24) NOT NULL,
password_hash VARCHAR(255) NOT NULL, -- scrypt$N$r$p$salt_b64$hash_b64
role ENUM('player','mod','admin','owner') NOT NULL DEFAULT 'player',
license VARCHAR(64) NULL, -- Cfx license: bound on first login
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
last_login_at DATETIME NULL,
last_ip VARCHAR(45) NULL,
banned TINYINT(1) NOT NULL DEFAULT 0,
ban_reason VARCHAR(255) NULL,
ban_until DATETIME NULL, -- NULL + banned=1 => permanent
PRIMARY KEY (id),
UNIQUE KEY uq_accounts_username (username),
KEY idx_accounts_license (license)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- Brute-force throttling. One row per (identity, window); pruned by the server.
CREATE TABLE IF NOT EXISTS auth_attempts (
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
identity VARCHAR(64) NOT NULL, -- license or username, lowercased
ip VARCHAR(45) NULL,
success TINYINT(1) NOT NULL DEFAULT 0,
at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id),
KEY idx_attempts_identity_at (identity, at)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE IF NOT EXISTS characters (
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
account_id INT UNSIGNED NOT NULL,
slot TINYINT UNSIGNED NOT NULL DEFAULT 0,
first_name VARCHAR(24) NOT NULL,
last_name VARCHAR(24) NOT NULL,
dob DATE NOT NULL,
gender ENUM('m','f') NOT NULL DEFAULT 'm',
backstory TEXT NULL,
appearance MEDIUMTEXT NULL, -- JSON: model, face blend, features, overlays, clothing
position VARCHAR(128) NULL, -- JSON: {x,y,z,h}
cash BIGINT NOT NULL DEFAULT 500,
bank BIGINT NOT NULL DEFAULT 2500,
health SMALLINT NOT NULL DEFAULT 200,
armour SMALLINT NOT NULL DEFAULT 0,
job VARCHAR(32) NOT NULL DEFAULT 'unemployed',
job_grade TINYINT UNSIGNED NOT NULL DEFAULT 0,
needs VARCHAR(128) NULL, -- JSON: {hunger,thirst,stress}
playtime INT UNSIGNED NOT NULL DEFAULT 0, -- seconds
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
last_played_at DATETIME NULL,
deleted TINYINT(1) NOT NULL DEFAULT 0,
PRIMARY KEY (id),
UNIQUE KEY uq_char_name (first_name, last_name),
KEY idx_char_account (account_id, deleted),
CONSTRAINT fk_char_account FOREIGN KEY (account_id) REFERENCES accounts(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- Every money movement is journalled; cash/bank on `characters` is the running total.
CREATE TABLE IF NOT EXISTS transactions (
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
character_id INT UNSIGNED NOT NULL,
account_kind ENUM('cash','bank') NOT NULL,
delta BIGINT NOT NULL,
balance_after BIGINT NOT NULL,
reason VARCHAR(64) NOT NULL,
at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id),
KEY idx_tx_character (character_id, at),
CONSTRAINT fk_tx_character FOREIGN KEY (character_id) REFERENCES characters(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE IF NOT EXISTS inventory (
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
owner_kind ENUM('character','stash','ground','vehicle') NOT NULL,
owner_id VARCHAR(64) NOT NULL, -- character id, stash key, drop uuid, plate
slot SMALLINT UNSIGNED NOT NULL,
item VARCHAR(48) NOT NULL,
qty INT UNSIGNED NOT NULL,
meta VARCHAR(512) NULL, -- JSON: durability, serial, ...
PRIMARY KEY (id),
UNIQUE KEY uq_inv_slot (owner_kind, owner_id, slot),
KEY idx_inv_owner (owner_kind, owner_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE IF NOT EXISTS vehicles (
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
character_id INT UNSIGNED NOT NULL,
plate VARCHAR(12) NOT NULL,
model VARCHAR(48) NOT NULL,
props MEDIUMTEXT NULL, -- JSON: colours, mods, damage
fuel FLOAT NOT NULL DEFAULT 100,
garage VARCHAR(32) NOT NULL DEFAULT 'legion',
stored TINYINT(1) NOT NULL DEFAULT 1,
impounded TINYINT(1) NOT NULL DEFAULT 0,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id),
UNIQUE KEY uq_veh_plate (plate),
KEY idx_veh_character (character_id),
CONSTRAINT fk_veh_character FOREIGN KEY (character_id) REFERENCES characters(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
+12
View File
@@ -0,0 +1,12 @@
# Copy to /opt/fivem/data/secrets.cfg and chmod 600.
# This file is exec'd by server.cfg and must never be committed anywhere.
# Free key from https://keymaster.fivem.net
sv_licenseKey "cfxk_your_key_here"
# Database the rp_db driver connects to.
set rp_db_host "127.0.0.1"
set rp_db_port "3306"
set rp_db_user "rp"
set rp_db_pass "your_database_password"
set rp_db_name "rp"