Zurück zum Blog
Tutorial8 Min. Lesezeit

FiveM-System für Gastronomie: Küchen skripten

Betreibe Restaurants in FiveM. Entdecke Rezepte zum Herstellen, Kassenoberflächen, Lieferjobs und beliebte Gastronomie-Skripte für deine Stadt.

Agency Scripts

Gründer und leitender Entwickler bei Agency Scripts

Warum Restaurants das Roleplay bereichern

Essens- und Restaurantsysteme gehören zu den Features, die das soziale Miteinander auf einem FiveM-Roleplay-Server besonders fördern. Anders als Einzelaktivitäten wie Bergbau oder Angeln schaffen Restaurants natürliche Treffpunkte, an denen Spieler gemeinsam kochen, bedienen und essen. Ein gut durchdachtes Restaurantsystem bietet Zivilisten einen sinnvollen Beruf ohne kriminelle Aktivitäten, gibt Charakteren einen Grund, regelmäßig bestimmte Orte aufzusuchen, und schafft durch den Einkauf von Zutaten einen Geldabfluss. In Kombination mit Landwirtschafts- oder Jagdskripten entstehen außerdem Lieferketten: Ein Spieler baut Tomaten an, ein anderer liefert sie und ein dritter verarbeitet sie zu einem Burger. Diese miteinander verknüpften Spielabläufe machen einen lebendigen Server aus, auf dem Spieler nicht einfach immer wieder dieselbe Route abarbeiten. Die Speisen selbst können vorübergehende Boni auf Gesundheit, Ausdauer oder Rüstungsregeneration gewähren und machen Restaurants so für alle Spieler auf dem Server relevant, unabhängig von Beruf oder Fraktion.

Restaurantkonfiguration und Menüs

Lege zunächst deine Restaurantstandorte, ihre Menüs und die für die einzelnen Gerichte benötigten Zutaten fest. Mit einer datenbasierten Konfiguration können Serverbesitzer neue Restaurants hinzufügen, ohne die Kernlogik anzupassen. Jedes Restaurant sollte durch sein Menü, seine Einrichtungsgegenstände und die Uniformen des NPC-Personals eine eigene Identität erhalten. Richte deine Konfiguration so ein, dass für jeden Menüpunkt die benötigten Zutaten, die Zubereitungszeit, der Verkaufspreis und etwaige Boni für den Konsumenten angegeben sind. So kannst du die Wirtschaft rund ums Essen ausbalancieren, indem du Konfigurationswerte anpasst, statt den Code neu zu schreiben:

Config.Restaurants = {
    ['burgershot'] = {
        label = 'Burger Shot',
        blip = { sprite = 106, color = 1, scale = 0.8 },
        zones = {
            counter = vector3(-1196.42, -894.04, 13.98),
            kitchen = vector3(-1199.71, -897.12, 13.98),
            storage = vector3(-1202.84, -899.35, 13.98),
        },
        menu = {
            {
                item = 'bleeder_burger',
                label = 'Bleeder Burger',
                price = 25,
                ingredients = {
                    { item = 'raw_patty', amount = 2 },
                    { item = 'burger_bun', amount = 1 },
                    { item = 'lettuce', amount = 1 },
                    { item = 'cheese_slice', amount = 2 },
                },
                craftTime = 8000,
                buffs = {
                    hunger = 45,
                    thirst = 5,
                    armor_regen = { amount = 2, duration = 120 }
                }
            },
            {
                item = 'heartstopper',
                label = 'Heart Stopper',
                price = 40,
                ingredients = {
                    { item = 'raw_patty', amount = 3 },
                    { item = 'burger_bun', amount = 1 },
                    { item = 'bacon', amount = 4 },
                    { item = 'cheese_slice', amount = 3 },
                    { item = 'onion_ring', amount = 2 },
                },
                craftTime = 12000,
                buffs = {
                    hunger = 80,
                    thirst = -10,
                    stamina_boost = { amount = 15, duration = 180 }
                }
            },
        },
        requiredJob = 'burgershot',
    },
}

Die zones Die Tabelle unterteilt das Restaurant in Funktionsbereiche. Im Thekenbereich geben Kunden ihre Bestellungen auf und nehmen ihr Essen entgegen. Der Küchenbereich ist Angestellten vorbehalten, die dort Gerichte zubereiten. Im Lagerbereich werden Zutaten aufbewahrt und verwaltet. Durch diese räumliche Trennung entsteht ein realistischer Arbeitsablauf, bei dem ein Koch Kunden nicht direkt am Herd bedienen kann. So ergibt sich eine natürliche Zusammenarbeit zwischen Service- und Küchenpersonal.

Kochmechaniken und Zubereitungsablauf

Der Kochvorgang sollte interaktiv sein, ohne zur lästigen Pflicht zu werden. Wenn ein Spieler mit der Zubereitung eines Gerichts beginnt, prüfe, ob alle benötigten Zutaten im Lagerbestand des Restaurants vorhanden sind, ziehe sie ab und starte einen Fortschrittsbalken oder eine Minispielsequenz. Einfache Fortschrittsbalken eignen sich für grundlegende Gerichte. Fähigkeitsprüfungen in Minispielen für Premiumgerichte vermitteln hingegen ein Gefühl von Können und verhindern AFK-Ausnutzung beim Kochen. Verwende für die Kochanimation passende GTA-Natives, etwa Szenarien am Grill oder an der Küchentheke, damit Beobachter in der Nähe sehen, was der Spieler gerade macht:

function StartCooking(restaurantId, menuIndex)
    local restaurant = Config.Restaurants[restaurantId]
    local recipe = restaurant.menu[menuIndex]

    -- Check ingredients in storage
    local hasAll = lib.callback.await('restaurant:checkIngredients', false,
        restaurantId, recipe.ingredients)

    if not hasAll then
        lib.notify({ description = 'Missing ingredients!', type = 'error' })
        return
    end

    -- Lock player into cooking animation
    local playerPed = PlayerPedId()
    local animDict = 'mini@repair'
    lib.requestAnimDict(animDict)
    TaskPlayAnim(playerPed, animDict, 'fixing_a_player', 8.0, -8.0,
        -1, 1, 0, false, false, false)

    -- Cooking progress with skill check
    local success = lib.skillCheck(
        {'easy', 'easy', 'medium'},
        {'w', 'a', 's', 'd'}
    )

    ClearPedTasks(playerPed)

    if success then
        TriggerServerEvent('restaurant:finishCooking', restaurantId, menuIndex)
        lib.notify({ description = 'Cooked: ' .. recipe.label, type = 'success' })
    else
        -- Failed cooking wastes some ingredients
        TriggerServerEvent('restaurant:failedCooking', restaurantId, menuIndex)
        lib.notify({ description = 'Burnt the food! Some ingredients wasted.',
            type = 'error' })
    end
end

Die Fähigkeitsprüfung bringt ein Risiko-Ertrags-Element ins Kochen. Bei einem Fehlversuch sollte nur ein Teil der Zutaten verloren gehen, damit neue Spieler nicht zu stark bestraft werden und sich die Verbesserung ihrer Fähigkeiten trotzdem lohnt. Du kannst den Schwierigkeitsgrad an den Wert des Gerichts anpassen. Günstige Gerichte lassen sich einfach zubereiten, während teure Spezialitäten echte Aufmerksamkeit erfordern. So entsteht ein natürlicher Fortschritt: Neue Angestellte beginnen mit einfachen Gerichten und arbeiten sich bis zum Premiumangebot vor.

Zutaten-Lieferkette

Restaurants benötigen einen stetigen Nachschub an Zutaten. Wie Spieler diese Zutaten beschaffen, prägt einen großen Teil des Spielablaufs. Es gibt drei gängige Ansätze: Einkauf bei Großhandels-NPCs, Beschaffung über von Spielern betriebene Farmen oder Jagd und ein Hybridmodell. Der Großhandelsansatz ist einfacher umzusetzen und garantiert die Verfügbarkeit, bietet aber kaum Interaktion zwischen Spielern. Die Beschaffung von anderen Spielern schafft enge wirtschaftliche Beziehungen, birgt jedoch das Risiko, dass Restaurants stillstehen, wenn die Lieferanten offline sind. Am besten eignet sich das Hybridmodell: Grundzutaten wie Brötchen, Öl und Gewürze kommen von NPCs, während Premiumzutaten wie frisches Fleisch, Bio-Gemüse und besondere Soßen über Spieleraktivitäten beschafft werden müssen. So können Restaurants jederzeit einen grundlegenden Betrieb gewährleisten und zugleich die gesamte Lieferkette belohnen, wenn alle Teile zusammenkommen. Implementiere für jedes Restaurant ein Lagersystem, das Zutatenmengen erfasst und Managern ermöglicht, Großhandelsbestellungen aufzugeben, deren Kosten vom Bankkonto des Restaurants abgezogen werden:

RegisterNetEvent('restaurant:orderSupplies', function(restaurantId, order)
    local src = source
    local Player = QBCore.Functions.GetPlayer(src)

    -- Verify player is manager rank
    if Player.PlayerData.job.name ~= restaurantId then return end
    if Player.PlayerData.job.grade.level < 3 then
        TriggerClientEvent('QBCore:Notify', src,
            'Only managers can order supplies', 'error')
        return
    end

    -- Calculate total cost
    local totalCost = 0
    for _, item in ipairs(order) do
        local wholesalePrice = Config.WholesalePrices[item.name]
        if wholesalePrice then
            totalCost = totalCost + (wholesalePrice * item.amount)
        end
    end

    -- Deduct from restaurant bank account
    local balance = exports['qb-management']:GetAccount(restaurantId)
    if balance < totalCost then
        TriggerClientEvent('QBCore:Notify', src,
            'Insufficient restaurant funds', 'error')
        return
    end

    exports['qb-management']:RemoveMoney(restaurantId, totalCost)

    -- Add items to restaurant storage
    for _, item in ipairs(order) do
        AddToRestaurantStorage(restaurantId, item.name, item.amount)
    end

    TriggerClientEvent('QBCore:Notify', src,
        string.format('Order placed! $%d deducted', totalCost), 'success')
end)

Kundenbestellungen und Serviceablauf

Das Kundenerlebnis sollte reibungslos ablaufen, egal ob Kunden bei einem NPC-Kassierer oder einem Angestellten bestellen. Wenn sich ein Kunde dem Thekenbereich nähert, zeige eine Menü-UI mit verfügbaren Gerichten, Preisen und Beschreibungen aktiver Boni an. In Restaurants mit Spielerpersonal sollte die Bestellung an die Küchenanzeige weitergeleitet werden, damit Köche eingehende Bestellungen in Echtzeit sehen. Implementiere ein Bestellsystem, das jede Bestellung vom Aufgeben über die Zubereitung bis zur Übergabe verfolgt. So entsteht eine Fast-Food-Simulation, in der sich während Stoßzeiten Bestellungen in der Küche stauen und für authentischen Druck beim Kochen sorgen. Zeige Kunden den Bestellstatus mit einfachen Anzeigen: bestellt, in Zubereitung, abholbereit. Wenn das Essen fertig ist, benachrichtige den Kunden und lass ihn die Bestellung an der Theke abholen. Für ein besonders hochwertiges Erlebnis können Spieler im Service das Essen direkt an sitzende Gäste bringen und je nach Serviergeschwindigkeit Trinkgeld verdienen.

Essensboni und Verzehreffekte

Speisen sollten über die reine Hungerregeneration hinaus sinnvolle Vorteile im Spiel bieten. Implementiere ein Bonussystem, bei dem verschiedene Gerichte vorübergehende Statusverbesserungen verleihen, damit Spieler vor Aktivitäten strategisch essen. Eine ausdauersteigernde Mahlzeit vor einer Verfolgung zu Fuß, ein Gericht zur Rüstungsregeneration vor einem Raubüberfall oder eine Mahlzeit, die nach einem Kampf die Gesundheit über Zeit wiederherstellt, machen Speisen in der Serverwirtschaft wirklich wertvoll. Erfasse aktive Boni pro Spieler und zeige sie im HUD an, damit Spieler wissen, welche Effekte gerade aktiv sind und wann sie ablaufen:

local activeBuffs = {}

function ApplyFoodBuff(buffType, amount, duration)
    -- Remove existing buff of same type
    if activeBuffs[buffType] then
        activeBuffs[buffType].active = false
    end

    activeBuffs[buffType] = {
        amount = amount,
        endTime = GetGameTimer() + (duration * 1000),
        active = true
    }

    -- Send buff data to HUD
    SendNUIMessage({
        action = 'addBuff',
        buffType = buffType,
        amount = amount,
        duration = duration
    })

    -- Create buff application thread
    CreateThread(function()
        local buff = activeBuffs[buffType]
        while buff.active and GetGameTimer() < buff.endTime do
            if buffType == 'armor_regen' then
                local current = GetPedArmour(PlayerPedId())
                if current < 100 then
                    SetPedArmour(PlayerPedId(), math.min(100, current + amount))
                end
            elseif buffType == 'stamina_boost' then
                RestorePlayerStamina(PlayerId(), amount * 0.1)
            elseif buffType == 'health_regen' then
                local current = GetEntityHealth(PlayerPedId())
                local max = GetEntityMaxHealth(PlayerPedId())
                if current < max then
                    SetEntityHealth(PlayerPedId(), math.min(max, current + amount))
                end
            end
            Wait(1000)
        end

        activeBuffs[buffType] = nil
        SendNUIMessage({ action = 'removeBuff', buffType = buffType })
    end)
end

Balanciere Essensboni sorgfältig aus, damit sie das Gameplay bereichern, ohne unverzichtbar zu werden. Boni sollten einen spürbaren Vorteil bieten, aber nicht so stark sein, dass Spieler vor jeder Aktivität unbedingt essen müssen. Halte die Dauer mit zwei bis fünf Minuten moderat, damit die Wirtschaft rund um die Boni aktiv bleibt. Erwäge, abnehmende Erträge einzuführen, wenn dieselbe Speise innerhalb kurzer Zeit wiederholt verzehrt wird, um das Ausnutzen gestapelter Boni zu verhindern.

Mitarbeiterverwaltung und Gehaltsabrechnung

Ein Restaurantsystem braucht eine klare Hierarchie mit unterschiedlichen Rollen und Berechtigungen. Lege mindestens drei Stufen fest: Mitarbeiter, Aufsichtsperson und Manager. Mitarbeiter können Gerichte zubereiten und Kunden bedienen. Aufsichtspersonen können zusätzlich zum Aufgabenbereich der Mitarbeiter den Zutatenbestand verwalten und Bestellungen freigeben. Manager haben volle Kontrolle, einschließlich der Einstellung und Entlassung von Mitarbeitern, der Festlegung von Preisen und des Zugriffs auf das Bankkonto des Restaurants. Verknüpfe die Gehaltsabrechnung mit dem Umsatz des Restaurants, damit Mitarbeiter ein Grundgehalt sowie eine Provision für Gerichte erhalten, die sie selbst zubereiten oder servieren. Das fördert die aktive Beteiligung statt bloßen AFK-Einloggens. Erfasse individuelle Mitarbeiterstatistiken wie zubereitete Gerichte, bediente Kunden und erzielten Umsatz. So kannst du Bestenlisten und Leistungsbeurteilungen erstellen, die dem Beruf mehr Tiefe verleihen.

Performance-Optimierung

Restaurantsysteme umfassen mehrere Interaktionsbereiche, NPC-Peds, Objekt-Props und die Auftragsverfolgung in Echtzeit. Ohne sorgfältige Optimierung kann das die Client-Performance beeinträchtigen. Verwende Interaktionen über ein Target-System statt entfernungsbasierter Markerprüfungen, um Koordinatenberechnungen in jedem Frame zu vermeiden. Rendere Props im Restaurantinnenraum nur, wenn sich Spieler im Gebäude befinden, indem du IsPlayerInScope Prüfungen verwendest. Bündle deine NUI-Nachrichten für die Bestellanzeige, statt bei jeder Änderung eine einzelne Aktualisierung zu senden. Halte serverseitig die Lagerbestände der Restaurants im Arbeitsspeicher vor und schreibe sie in festgelegten Zeitabständen in die Datenbank, statt nach jeder Zutatenänderung. Wenn mehrere Restaurants gleichzeitig aktiv sind, verteile ihre Datenbank-Synchronisierungen zeitlich, um Schreibspitzen zu vermeiden. Entferne beim Stoppen der Ressource alle Blips, Props und NPC-Entitäten, damit sich durch Neustarts keine verwaisten Entitäten ansammeln. Teste dein System unter Last mit mehreren aktiven Restaurants, mehreren gleichzeitig arbeitenden Köchen und einem stetigen Strom von Kundenbestellungen. So findest du Engpässe, bevor deine Spieler dich darauf aufmerksam machen.

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.