Datenbank
createDatabaseTables installiert beim Start deine sql/main.sql; WriteQueue führt Datenbank-Schreibvorgänge nacheinander aus.
import { createDatabaseTables, WriteQueue } from "@aicore-fivem/lib/server";
import { mysql } from "@aicore-fivem/mysql";Die Abfragen selbst laufen über @aicore-fivem/mysql (mysql.query, single, scalar, insert, update, prepare, transaction): siehe Datenbank. Diese Seite behandelt die zwei Lib-Helfer drumherum.
Keine Lua-Zwillinge: Lua-Ressourcen nutzen die oxmysql-API von ai-mysql (MySQL.query.await, ...) und installieren ihre Tabellen selbst.
createDatabaseTables
Erstellt die fehlenden Tabellen und fügt die fehlenden Spalten aus der SQL-Datei deiner Ressource hinzu. Rufe es einmal beim Start auf, vor der ersten Abfrage, die die Tabellen braucht. Es wartet zuerst auf die Datenbankverbindung.
Seite: Server · Wartet: ja (Promise)
createDatabaseTables(resource: string, file: string): Promise<void>Parameter
Prop
Type
Was es anwendet
- Nur
CREATE TABLE IF NOT EXISTS-Anweisungen; jede andere Anweisung wird mit einer Warnung übersprungen. Anweisungen enden mit;am Zeilenende;--- und/* */-Kommentare werden ignoriert. - Eine Tabelle, die nicht existiert, wird mit der vollständigen Anweisung erstellt (Spalten und Schlüssel).
- Bei einer bestehenden Tabelle wird jede fehlende Spalte mit
ALTER TABLE ... ADD COLUMNhinzugefügt. - Es löscht, benennt oder ändert nie eine Spalte und fügt einer bestehenden Tabelle nie Schlüssel oder Indizes hinzu: Plane deine Indizes vor dem ersten Release.
Rückgabewert
Promise<void>: wird erfüllt, wenn jede Anweisung angewendet wurde. Wird abgelehnt, wenn die Datei fehlt (<resource>/<file> not found) oder eine Abfrage fehlschlägt.
Beispiel
CREATE TABLE IF NOT EXISTS `ai_myshop_purchases` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`char_id` INT UNSIGNED NOT NULL,
`item` VARCHAR(64) NOT NULL,
`price` INT UNSIGNED NOT NULL,
`created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `char_id` (`char_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;import { createDatabaseTables } from "@aicore-fivem/lib/server";
import { createLogger } from "@aicore-fivem/lib/shared";
import { mysql } from "@aicore-fivem/mysql";
const resource = GetCurrentResourceName();
const log = createLogger(resource);
/** Reads and writes wait for this. */
export const tablesReady: Promise<void> = createDatabaseTables(resource, "sql/main.sql").catch((error: unknown) =>
log.error("database setup failed", error),
);
export async function addPurchase(charId: number, item: string, price: number) {
await tablesReady;
await mysql.insert("INSERT INTO ai_myshop_purchases (char_id, item, price) VALUES (?, ?, ?)", [charId, item, price]);
}Stelle deinen Tabellen die Ressource voran (ai_<name>_...) und beende jede Tabelle mit ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci, wie die sql/main.sql der Vorlage.
WriteQueue
Führt Datenbank-Schreibvorgänge nacheinander aus, in der Reihenfolge, in der du sie hinzufügst. Das Muster: Der Server-Speicher ist die Wahrheit, die Tabelle folgt in Reihenfolge. Ein fehlgeschlagener Schreibvorgang wird an deinen Fehler-Handler gemeldet und hält die nachfolgenden nicht auf.
Seite: Server · Wartet: nein (idle() gibt ein Promise zurück)
new WriteQueue(onError: (label: string, error: unknown) => void)
push(label: string, task: () => Promise<unknown>): void
idle(): Promise<void>Prop
Type
Rückgabewert push: void. idle(): ein Promise, das erfüllt wird, wenn jeder bisher eingereihte Schreibvorgang fertig ist (warte darauf, bevor die Ressource stoppt oder vor einem Lesezugriff, der sie braucht).
Beispiel
import { WriteQueue, onCharacter, PlayerMap } from "@aicore-fivem/lib/server";
import { createLogger } from "@aicore-fivem/lib/shared";
import { mysql } from "@aicore-fivem/mysql";
const log = createLogger(GetCurrentResourceName());
const writes = new WriteQueue((label, error) => log.error(`database write failed (${label})`, error));
const xp = new PlayerMap<{ charId: number; points: number }>();
export function addXp(source: number, amount: number) {
const entry = xp.get(source);
if (!entry) return;
entry.points += amount; // zuerst der Speicher
const { charId, points } = entry;
writes.push(`xp:${charId}`, () => mysql.update("UPDATE ai_myjob_xp SET points = ? WHERE char_id = ?", [points, charId]));
}
onCharacter({
loaded: (source, character) => xp.set(source, { charId: character.id, points: 0 }),
});Admin-Panel
AdminPanel und DataFile: die Einstellungen deines Skripts ins Admin-Panel von ai-core bringen, sie lesen, auf Änderungen reagieren und Panel-Inhalte in data/*.json speichern.
Lib: Shared und fivem
@aicore-fivem/lib/shared und /fivem: die Helfer, die auf beiden Seiten funktionieren, wofür jeder Einstieg da ist, und jede Themenseite.