Zurück zum Blog
Tutorial10 Min. Lesezeit

FiveM-Banking- und Geldautomaten-Skripte: Realistische Geldsysteme

Gestalte mit FiveM-Banking- und Geldautomaten-Skripten eine glaubwürdige Wirtschaft. Mit Überweisungen, UI-Ideen, Ressourcen und Framework-Anbindung.

Agency Scripts

Gründer und leitender Entwickler bei Agency Scripts

Architektur eines Banksystems

Ein Banksystem bildet das finanzielle Rückgrat jedes FiveM-Rollenspielservers. Es verwaltet alles, von einfachen Bareinzahlungen bis hin zu komplexen Überweisungen zwischen Spielern und gemeinsamen Organisationskonten. Die meisten Frameworks wie QBCore und ESX bieten eine grundlegende Geldverwaltung. Ein dediziertes Banksystem erweitert diese um eine vollständige Kontoverwaltung, Transaktionsprotokolle und eine ausgefeilte Geldautomatenoberfläche, die Spieler in die finanzielle Seite des Rollenspiels eintauchen lässt. Die Architektur besteht aus drei Ebenen: Die Datenbank speichert Kontostände und Transaktionsdaten, der Server validiert jeden Finanzvorgang und setzt Geschäftsregeln durch, und der Client stellt über NUI die Oberflächen für Geldautomaten und Bankschalter bereit. Jeder Geldvorgang muss serverseitig abgewickelt werden, denn Manipulationen am Geld auf dem Client sind die häufigste Exploit-Methode auf FiveM-Servern. Selbst die Anzeige eines Kontostands sollte über einen Server-Callback erfolgen, niemals anhand zwischengespeicherter Client-Daten, die manipuliert werden könnten.

Datenbankschema für Bankgeschäfte

Deine Bankdatenbank muss persönliche Konten, Gemeinschaftskonten für Organisationen und Unternehmen sowie ein vollständiges Transaktionsprotokoll unterstützen. Das Transaktionsprotokoll ist unverzichtbar, denn es dient zugleich als Funktion für Spieler und als Admin-Tool zur Untersuchung von Geld-Exploits. Entwirf dein Schema für einen hohen Durchsatz, denn auf stark frequentierten Servern können zu Spitzenzeiten Hunderte Transaktionen pro Minute verarbeitet werden:

CREATE TABLE IF NOT EXISTS bank_accounts (
    id INT AUTO_INCREMENT PRIMARY KEY,
    account_number VARCHAR(20) UNIQUE NOT NULL,
    owner_citizenid VARCHAR(50) NOT NULL,
    account_type ENUM('personal', 'business', 'gang', 'shared') DEFAULT 'personal',
    balance BIGINT DEFAULT 0,
    account_name VARCHAR(100) DEFAULT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    is_frozen BOOLEAN DEFAULT FALSE,
    INDEX idx_owner (owner_citizenid),
    INDEX idx_type (account_type)
);

CREATE TABLE IF NOT EXISTS bank_transactions (
    id BIGINT AUTO_INCREMENT PRIMARY KEY,
    account_id INT NOT NULL,
    type ENUM('deposit', 'withdraw', 'transfer_in', 'transfer_out', 'paycheck', 'purchase') NOT NULL,
    amount BIGINT NOT NULL,
    balance_after BIGINT NOT NULL,
    description VARCHAR(255) DEFAULT NULL,
    other_account VARCHAR(20) DEFAULT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    INDEX idx_account (account_id),
    INDEX idx_created (created_at),
    FOREIGN KEY (account_id) REFERENCES bank_accounts(id)
);

CREATE TABLE IF NOT EXISTS bank_account_access (
    account_id INT NOT NULL,
    citizenid VARCHAR(50) NOT NULL,
    permission ENUM('view', 'withdraw', 'full') DEFAULT 'view',
    PRIMARY KEY (account_id, citizenid),
    FOREIGN KEY (account_id) REFERENCES bank_accounts(id)
);

Die bank_account_access Die Tabelle ermöglicht Gemeinschaftskonten, bei denen mehrere Spieler unterschiedliche Berechtigungsstufen haben können. Ein Gang-Anführer kann beispielsweise uneingeschränkten Zugriff auf die Gang-Kasse haben, während reguläre Mitglieder nur den Kontostand einsehen können. Mit BIGINT bei Kontostandfeldern verhinderst du Überläufe auf Servern mit aufgeblähter Wirtschaft, auf denen Spielerkontostände Milliarden erreichen können.

Serverseitige Transaktionslogik

Jede Finanztransaktion muss atomar sein und serverseitig validiert werden. Verwende Datenbanktransaktionen, um sicherzustellen, dass bei Überweisungen niemals Geld erzeugt oder vernichtet wird. Wenn Spieler A Geld an Spieler B sendet, müssen sowohl der Abzug bei A als auch die Gutschrift bei B erfolgreich sein, andernfalls darf keiner der beiden Vorgänge ausgeführt werden. Implementiere Prüfungen auf ausreichendes Guthaben, gesperrte Konten, tägliche Überweisungslimits und Mindestbeträge. Hier ist eine sichere Überweisungsimplementierung:

RegisterNetEvent('banking:server:transfer', function(targetAccount, amount, description)
    local src = source
    local Player = QBCore.Functions.GetPlayer(src)
    if not Player then return end

    amount = math.floor(tonumber(amount) or 0)
    if amount <= 0 then
        TriggerClientEvent('QBCore:Notify', src, 'Invalid amount', 'error')
        return
    end

    local citizenid = Player.PlayerData.citizenid
    local senderAccount = GetPlayerPrimaryAccount(citizenid)

    if not senderAccount or senderAccount.is_frozen then
        TriggerClientEvent('QBCore:Notify', src, 'Account unavailable', 'error')
        return
    end

    if senderAccount.balance < amount then
        TriggerClientEvent('QBCore:Notify', src, 'Insufficient funds', 'error')
        return
    end

    -- Check daily transfer limit
    local todayTransfers = GetDailyTransferTotal(senderAccount.id)
    if todayTransfers + amount > Config.DailyTransferLimit then
        TriggerClientEvent('QBCore:Notify', src, 'Daily limit exceeded', 'error')
        return
    end

    -- Atomic transfer using database transaction
    local success = MySQL.transaction.await({
        {
            query = 'UPDATE bank_accounts SET balance = balance - ? WHERE id = ? AND balance >= ?',
            values = {amount, senderAccount.id, amount}
        },
        {
            query = 'UPDATE bank_accounts SET balance = balance + ? WHERE account_number = ?',
            values = {amount, targetAccount}
        },
        {
            query = 'INSERT INTO bank_transactions (account_id, type, amount, balance_after, description, other_account) VALUES (?, "transfer_out", ?, (SELECT balance FROM bank_accounts WHERE id = ?), ?, ?)',
            values = {senderAccount.id, amount, senderAccount.id, description or 'Transfer', targetAccount}
        },
    })

    if success then
        TriggerClientEvent('QBCore:Notify', src, 'Transfer complete: $' .. amount, 'success')
        TriggerClientEvent('banking:client:refreshBalance', src)
    else
        TriggerClientEvent('QBCore:Notify', src, 'Transfer failed', 'error')
    end
end)

Beachte die WHERE balance >= ? Klausel in der Abfrage zum Geldabzug. Sie dient als letzte Schutzmaßnahme gegen Race Conditions, bei denen zwei gleichzeitige Überweisungen das Konto überziehen könnten. Diese Prüfung auf Datenbankebene ist unverzichtbar, obwohl du den Kontostand bereits in Lua überprüfst, denn zwischen deiner Prüfung und der tatsächlichen Aktualisierung können mehrere Anfragen eingehen.

Benutzeroberfläche für Geldautomaten

Die Geldautomatenoberfläche ist ein kompaktes NUI-Panel, das schnellen Zugriff auf die wichtigsten Bankfunktionen bietet: Kontostand prüfen, Bargeld einzahlen, Bargeld abheben und Geld überweisen. Halte das Design übersichtlich und vertraut, denn Spieler erwarten intuitiv, dass ein Geldautomat wie sein reales Gegenstück funktioniert. Zeige den aktuellen Kontostand gut sichtbar oben an und platziere darunter Schaltflächen für jede Aktion. Die Ansichten für Ein- und Auszahlungen sollten neben einem Eingabefeld für einen individuellen Betrag vorausgewählte Beträge für gängige Werte wie $100, $500, $1000 und $5000 anbieten. Bei Überweisungen sollten Felder für die Kontonummer des Empfängers und den Betrag sowie ein optionales Mitteilungsfeld vorhanden sein. Zeige vor der Ausführung jeder Transaktion einen Bestätigungsschritt an, damit versehentliche Klicks Spieler kein Geld kosten. Füge eine Liste der letzten Transaktionen hinzu, die die letzten 10 Einträge anzeigt. So können Spieler ihre Finanzaktivitäten prüfen, ohne eine Bankfiliale aufsuchen zu müssen. Die Geldautomatenoberfläche sollte schnell reagieren. Lade Kontostand und Transaktionsdaten mit einem einzigen Callback, wenn das Menü geöffnet wird, statt für jede Information eine separate Anfrage zu stellen.

Interaktion mit Geldautomaten einrichten

Platziere Interaktionspunkte an den vorhandenen Geldautomaten-Props auf der gesamten GTA-Karte. FiveM stellt eine Liste von Hashes für Geldautomatenmodelle bereit, über die du iterieren kannst, um alle Geldautomaten-Props in der Spielwelt zu finden. Verwende für eine saubere Interaktion ein Target-System wie ox_target oder greife alternativ auf Näherungsprüfungen in der Nähe jedes Geldautomaten-Props zurück. Wenn der Spieler mit einem Geldautomaten interagiert, spiele eine Animation ab, in der er den Geldautomaten benutzt, und öffne anschließend das NUI-Panel:

local atmModels = {
    'prop_atm_01', 'prop_atm_02', 'prop_atm_03',
    'prop_fleeca_atm', 'v_5_b_atm1'
}

-- Using ox_target for ATM interaction
for _, model in ipairs(atmModels) do
    exports.ox_target:addModel(GetHashKey(model), {
        {
            name = 'use_atm',
            icon = 'fas fa-credit-card',
            label = 'Use ATM',
            onSelect = function(data)
                local ped = PlayerPedId()
                local atmCoords = GetEntityCoords(data.entity)

                -- Face the ATM
                TaskTurnPedToFaceCoord(ped, atmCoords.x, atmCoords.y, atmCoords.z, 1000)
                Wait(1000)

                -- Play ATM animation
                RequestAnimDict('mini@atmenter')
                while not HasAnimDictLoaded('mini@atmenter') do Wait(10) end
                TaskPlayAnim(ped, 'mini@atmenter', 'enter', 8.0, -8.0, -1, 0, 0, false, false, false)

                -- Open ATM UI
                QBCore.Functions.TriggerCallback('banking:server:getAccountData', function(data)
                    SetNuiFocus(true, true)
                    SendNUIMessage({
                        action = 'openATM',
                        balance = data.balance,
                        transactions = data.recentTransactions,
                        accountNumber = data.accountNumber
                    })
                end)
            end
        }
    })
end

Transaktionsverlauf und Kontoauszüge

Der Transaktionsverlauf macht aus einem einfachen Ein- und Auszahlungsautomaten ein umfassendes Finanzverwaltungstool. Spieler sollten in Bankfilialen ihren vollständigen Transaktionsverlauf einsehen und nach Zeitraum, Transaktionstyp oder Betrag filtern können. Jeder Transaktionseintrag sollte Datum, Typ, Betrag, resultierenden Kontostand, Beschreibung und bei Überweisungen die beteiligte Gegenpartei anzeigen. Implementiere die Paginierung serverseitig, denn Tausende von Transaktionen auf einmal zu laden, friert den NUI-Frame ein und erhöht die Speicherauslastung des Servers stark. Gib 20-30 Transaktionen pro Seite zurück und ermögliche es dem Spieler, bei Bedarf weitere zu laden. Biete in Bankfilialen zusätzliche Funktionen an, die über das Angebot von Geldautomaten hinausgehen, etwa das Eröffnen neuer Konten, die Verwaltung von Berechtigungen für Gemeinschaftskonten, das Erstellen von Kontoauszügen für einen bestimmten Zeitraum und die Beantragung von Krediten, wenn dein Server diese Funktion unterstützt. Speichere Transaktionsbeschreibungen als verständliche Texte, damit automatische Transaktionen von Jobs, Käufen in Geschäften und staatlichen Steuern klar und ohne zusätzlichen Kontext nachvollziehbar sind.

Mechaniken für Banküberfälle

Banküberfälle gehören zu den spannendsten Ereignissen auf jedem Rollenspielserver. Sie schaffen Situationen mit hohem Einsatz, an denen Kriminelle, Polizei, Geiselverhandler und Unbeteiligte beteiligt sind. Ein gut durchdachtes Überfallsystem umfasst mehrere Phasen: die Bank auskundschaften, den Überfall starten, Sicherheitssysteme mit Minispielen hacken oder aufbohren, die Beute verladen und mit der Polizei im Nacken fliehen. Lege zunächst fest, welche Banken überfallen werden können, welche Schwierigkeitsstufe sie haben, welche Abklingzeiten gelten und welche Gegenstände benötigt werden. Für den Überfall sollten bestimmte Werkzeuge erforderlich sein, etwa Thermit für Tresortüren, Hacking-Geräte für Sicherheitsanlagen und Seesäcke zum Transport der Beute. Implementiere Minispiele mit steigender Schwierigkeit für jede Sicherheitsebene. Ein fehlgeschlagener Hack löst zusätzliche Alarme aus oder führt dazu, dass der Tresor weiter abgeriegelt wird:

Config.BankRobberies = {
    ['fleeca_1'] = {
        label = 'Fleeca Bank - Legion Square',
        coords = vector3(149.73, -1042.65, 29.37),
        vault = vector3(144.87, -1044.16, 29.37),
        tier = 1,  -- 1=Fleeca, 2=Paleto, 3=Pacific Standard
        cooldown = 7200,  -- 2 hours
        minPolice = 3,
        requiredItems = {'electronickit', 'thermite'},
        reward = { min = 40000, max = 80000, markedBills = true },
        securityLayers = {
            { type = 'hack', difficulty = 'easy', time = 30 },
            { type = 'thermite', time = 10 },
            { type = 'drill', time = 45 },
        },
    },
    ['pacific_standard'] = {
        label = 'Pacific Standard Bank',
        coords = vector3(255.85, 225.60, 101.88),
        vault = vector3(262.20, 222.10, 101.68),
        tier = 3,
        cooldown = 14400,  -- 4 hours
        minPolice = 6,
        requiredItems = {'electronickit', 'thermite', 'advancedlaptop'},
        reward = { min = 200000, max = 400000, markedBills = true },
        securityLayers = {
            { type = 'hack', difficulty = 'hard', time = 20 },
            { type = 'hack', difficulty = 'hard', time = 20 },
            { type = 'thermite', time = 8 },
            { type = 'drill', time = 60 },
            { type = 'hack', difficulty = 'expert', time = 15 },
        },
    },
}

Verwende markierte Geldscheine als Belohnung für Überfälle statt sauberen Bargelds. So müssen Kriminelle das Geld in zusätzlichen Spielabläufen waschen, etwa an Geldwäsche-Standorten oder über den Umtausch von Schwarzgeld. Dadurch geht das Rollenspiel rund um den Überfall hinaus weiter und es entstehen Möglichkeiten für polizeiliche Ermittlungen. Benachrichtige bei Beginn eines Überfalls das Polizei-Dispatch-System und erfasse den Fortschritt serverseitig, damit Beamte je nach Fortschritt der Kriminellen taktisch reagieren können.

Sicherheit und Maßnahmen gegen Exploits

Finanzsysteme sind ein Hauptziel von Exploit-Nutzern, denn Geld verschafft direkt Macht im Spiel. Ergänze die bereits besprochene serverseitige Validierung um mehrere weitere Sicherheitsebenen. Begrenze die Rate aller Bank-Events, damit ein einzelner Spieler nicht Hunderte Einzahlungs- oder Überweisungsanfragen pro Sekunde auslösen kann. Protokolliere jede Finanztransaktion mit den Kennungen des auslösenden Spielers und einem Zeitstempel, damit Admins Geldflüsse zurückverfolgen und Duplikations-Exploits aufdecken können. Implementiere ein System zum Rückgängigmachen von Transaktionen, mit dem Admins betrügerische Transaktionen nach dem Entdecken von Exploits rückgängig machen können. Lege Höchstbeträge für einzelne Transaktionen und tägliche Gesamtl Limits fest, die sich nach dem Alter des Kontos und der gesamten Spielzeit des Spielers richten. So sind frisch erstellte Konten zum Geldwaschen weniger geeignet. Überwache verdächtige Muster wie schnelle Hin- und Rücküberweisungen zwischen zwei Konten, Einzahlungen, die innerhalb weniger Sekunden genau dem von einem anderen Spieler abgehobenen Betrag entsprechen, oder Kontostandserhöhungen ohne zugehörige Transaktionsdatensätze. Sende bei erkannter verdächtiger Aktivität Discord-Webhook-Benachrichtigungen, damit dein Moderationsteam in Echtzeit nachforschen kann, ohne auf Spielerberichte zu warten. Erwäge ein System für gesperrte Konten, mit dem Admins Konten während einer Untersuchung sperren und so verhindern können, dass das mutmaßlich erbeutete Geld ausgegeben oder überwiesen wird, während der Vorfall geklärt wird.

Integration in die Serverwirtschaft

Dein Banksystem sollte als zentrale Anlaufstelle für alle Geldflüsse auf dem Server dienen. Wickle Gehaltszahlungen über das Banksystem ab, damit Spieler ihren Lohn als Bankgutschrift erhalten. Der Transaktionsdatensatz sollte klar angeben, welcher Job wie viel gezahlt hat. Verbinde Einkäufe in Geschäften mit Bankabbuchungen, wenn Spieler mit Karte statt mit Bargeld zahlen. So entsteht ein nachvollziehbarer Beleg, der den Realismus erhöht und Spielern neben der einfachen Aufbewahrung einen Grund gibt, das Banksystem zu nutzen. Implementiere automatische Abbuchungen für wiederkehrende Kosten wie Grundsteuern, Fahrzeugversicherungen und Betriebsausgaben, die regelmäßig vom Bankkonto des Spielers abgehen. Reicht das Guthaben eines Spielers für eine automatische Zahlung nicht aus, sollte das System eine fehlgeschlagene Zahlung protokollieren und Konsequenzen auslösen, etwa Warnungen vor einer Beschlagnahmung von Eigentum oder den Verlust des Versicherungsschutzes. Verknüpfe das Banksystem mit deiner Telefon-Ressource, damit Spieler ihren Kontostand prüfen, die letzten Transaktionen ansehen und schnell Geld überweisen können, ohne einen Geldautomaten oder eine Bankfiliale aufsuchen zu müssen. Durch diese Integration wird das Banksystem von einer isolierten Funktion zum finanziellen Nervensystem, das alle wirtschaftlichen Aktivitäten auf deinem Server miteinander verbindet.

Das passende Script

Fertig für deinen Server, Updates inklusive.

Bereit loszulegen?

Hol dir die Scripts in unserem Shop, oder komm auf den Discord für Support, Updates und einen Blick auf das, was kommt.