>
Tutoriel 2026-05-08

Système de restauration et nourriture pour FiveM

TDYSKY

TDYSKY

Fondateur et développeur principal chez Agency Scripts

Pourquoi les systèmes de restauration améliorent le jeu de rôle

Les systèmes de restauration et de restauration font partie des fonctionnalités les plus socialement engageantes que tu puissies ajouter à un serveur de jeu de rôle FiveM. Contrairement aux activités solo comme l’exploitation minière ou la pêche, les restaurants créent des points de rassemblement organiques où les joueurs cuisinent, servent et mangent ensemble. Un système de restauration bien conçu donne aux joueurs civils un travail significatif qui n'implique pas de crime, donne aux personnages une raison de visiter régulièrement les lieux et introduit un puits d'économie grâce à l'achat d'ingrédients. Les restaurants créent également des chaînes d'approvisionnement lorsqu'ils sont combinés avec des scénarios d'agriculture ou de chasse, ce qui signifie qu'un joueur cultive des tomates, un autre les livre et un troisième les prépare dans un hamburger. Cette boucle de jeu interconnectée est ce qui sépare un serveur vivant d’un serveur où les joueurs suivent simplement le même itinéraire à plusieurs reprises. Les aliments eux-mêmes peuvent fournir des améliorations temporaires de santé, d'endurance ou de régénération d'armure, ce qui rend les restaurants pertinents pour chaque joueur du serveur, quel que soit son travail ou sa faction.

Configuration du restaurant et conception des menus

Commencez par définir les emplacements de tes restaurants, leurs menus et les ingrédients requis pour chaque plat. Une configuration basée sur les données permet aux propriétaires de serveurs d'ajouter de nouveaux restaurants sans modifier la logique de base. Chaque restaurant doit avoir une identité unique à travers ses offres de menu, ses accessoires intérieurs et les uniformes du personnel des PNJ. Structurez ton configuration de manière à ce que chaque élément de menu répertorie les ingrédients requis, le temps de fabrication, le prix de vente et les effets de buff qu'il accorde au consommateur. Cette approche signifie qu'équilibrer ton économie alimentaire revient à ajuster les valeurs de configuration plutôt qu'à réécrire le code :

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',
    },
}

Le zones La table sépare le restaurant en zones fonctionnelles. La zone du comptoir est l'endroit où les clients passent leurs commandes et reçoivent de la nourriture. Le coin cuisine est réservé aux salariés qui l'utilisent pour cuisiner des plats. La zone de stockage est l'endroit où les ingrédients sont stockés et gérés. Cette séparation spatiale impose un flux de travail réaliste dans lequel un cuisinier ne peut pas servir les clients directement depuis la cuisinière, créant ainsi un travail d'équipe naturel entre le personnel de réception et celui de cuisine.

Mécaniques de cuisine et flux de fabrication

Le processus de cuisson doit être interactif sans être fastidieux. Lorsqu'un joueur commence à cuisiner un article, vérifiez que tous les ingrédients requis existent dans l'inventaire de stockage du restaurant, soustrayez-les et lancez une barre de progression ou une séquence de mini-jeu. Des barres de progression simples fonctionnent pour les éléments de base, mais l'ajout de mini-jeux de contrôle de compétences pour les plats haut de gamme crée un sentiment de maîtrise et empêche les exploits culinaires AFK. L'animation culinaire doit utiliser des éléments natifs de GTA appropriés, comme les scénarios de barbecue ou de comptoir de cuisine, pour communiquer visuellement ce que fait le joueur aux observateurs à proximité :

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

Le mécanicien de contrôle de compétences ajoute un élément risque-récompense à la cuisine. Les tentatives ratées devraient gaspiller une partie des ingrédients plutôt que la totalité, de sorte que les nouveaux joueurs ne soient pas lourdement punis tout en les encourageant à améliorer leurs compétences. Tu peux adapter la difficulté en fonction de la valeur du plat, ce qui rend les plats bon marché faciles à cuisiner et les plats signature coûteux nécessitent une véritable attention. Cela crée une progression naturelle dans laquelle les nouveaux employés commencent avec des éléments simples et progressent jusqu'au menu premium.

Chaîne d'approvisionnement en ingrédients

Les restaurants ont besoin d’un flux constant d’ingrédients, et la manière dont les joueurs obtiennent ces ingrédients définit une partie importante de la boucle de jeu. Il existe trois approches courantes : l'achat auprès de vendeurs de PNJ en gros, l'approvisionnement auprès de fermes gérées par les joueurs ou la chasse, et un modèle hybride. L’approche de gros est plus simple à mettre en œuvre et garantit la disponibilité, mais elle manque d’interaction entre les joueurs. L'approvisionnement auprès d'autres acteurs crée des relations économiques riches, mais risque d'entraîner des interruptions de service dans les restaurants lorsque les fournisseurs sont hors ligne. Le modèle hybride fonctionne mieux : les ingrédients de base comme les petits pains, l'huile et les assaisonnements proviennent de PNJ, tandis que les ingrédients de qualité supérieure comme la viande fraîche, les légumes biologiques et les sauces spéciales doivent provenir des activités des joueurs. Cela garantit que les restaurants peuvent toujours fonctionner à un niveau de base tout en récompensant l’ensemble de la chaîne d’approvisionnement lorsque tous les éléments sont connectés. Mettre en place un système de stockage par restaurant qui suit les quantités d'ingrédients et permet aux gestionnaires de passer des commandes en gros qui sont déduites du compte bancaire du restaurant :

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)

Commande client et flux de service

L'expérience client doit être fluide, qu'il commande auprès d'un caissier d'un PNJ ou d'un employé d'un joueur. Lorsqu'un client s'approche de la zone de comptoir, affichez une interface utilisateur de menu affichant les articles disponibles avec leurs prix et toutes les descriptions de buffs actifs. Pour les restaurants dotés de joueurs, la commande doit être acheminée vers l'écran de la cuisine afin que les cuisiniers voient les commandes entrantes en temps réel. Mettez en œuvre un système de file d’attente de commandes qui suit chaque commande depuis le placement jusqu’à la préparation et la livraison. Cela crée une simulation de restauration rapide où la cuisine est sauvegardée pendant les périodes de pointe, ajoutant une pression authentique au rôle de cuisinier. Affichez l'état de la commande aux clients avec des indicateurs simples : commandé, en cours de cuisson, prêt à être récupéré. Lorsque la nourriture est prête, prévenez le client et laissez-le venir la chercher au comptoir. Pour une expérience premium, permettez aux serveurs joueurs de livrer de la nourriture directement aux clients assis à table, gagnant ainsi des pourboires en fonction de la rapidité du service.

Buffs alimentaires et effets de consommation

Les produits alimentaires devraient offrir des avantages de jeu significatifs au-delà de la simple restauration de la faim. Implémentez un système de buff dans lequel différents aliments accordent des modifications temporaires aux statistiques qui encouragent les joueurs à manger de manière stratégique avant les activités. Un repas pour augmenter l'endurance avant une course à pied, un plat de régénération d'armure avant un braquage ou un repas de récupération de santé au fil du temps après un combat rendent tous les aliments réellement précieux dans l'économie des serveurs. Suivez les buffs actifs par joueur et affichez-les dans le HUD afin que les joueurs sachent quels effets ils ont actuellement et quand ils expirent :

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

Équilibrez soigneusement les buffs alimentaires afin qu’ils améliorent le gameplay sans devenir obligatoires. Les buffs devraient offrir un avantage notable sans être si puissants que les joueurs se sentent obligés de manger avant chaque activité. Gardez une durée modérée, entre deux et cinq minutes, pour que l'économie de buff reste active. Envisagez d'ajouter des rendements décroissants si le même aliment est consommé à plusieurs reprises sur une courte période afin d'éviter les exploits d'empilement de buffs.

Gestion des employés et paie

Un système de restaurant a besoin d’une hiérarchie appropriée avec différents rôles et autorisations. Définissez au moins trois niveaux : travailleur, superviseur et gestionnaire. Les travailleurs peuvent cuisiner des plats et servir les clients. Les superviseurs peuvent faire tout ce que font les travailleurs, gérer le stockage des ingrédients et approuver les commandes. Les gestionnaires ont un contrôle total, y compris l'embauche et le licenciement des employés, la fixation des prix et l'accès au compte bancaire du restaurant. Liez la masse salariale aux revenus du restaurant afin que les employés gagnent un salaire de base plus une commission sur les articles qu'ils cuisinent ou servent personnellement. Cela encourage la participation active plutôt que le pointage AFK. Suivez les statistiques individuelles des employés telles que les articles cuisinés, les clients servis et les revenus générés pour créer des classements et des évaluations de performances qui ajoutent de la profondeur à l'expérience de travail.

Optimisation des performances

Les systèmes de restauration impliquent plusieurs zones d'interaction, des PNJ, des objets accessoires et un suivi des commandes en temps réel qui peuvent nuire aux performances des clients s'ils ne sont pas soigneusement optimisés. Utilisez les interactions du système cible plutôt que les contrôles de distance basés sur des marqueurs pour éliminer les calculs de coordonnées par image. Ne restituez les accessoires intérieurs du restaurant que lorsque les joueurs sont à l'intérieur du bâtiment en utilisant IsPlayerInScope chèques. Regroupez tes messages NUI pour l'affichage de la file d'attente des commandes plutôt que d'envoyer des mises à jour individuelles pour chaque changement de commande. Côté serveur, mettez en cache les inventaires de stockage du restaurant en mémoire et écrivez dans la base de données à intervalles réguliers plutôt qu'après chaque changement d'ingrédient. Lorsque plusieurs restaurants sont actifs simultanément, échelonnez leurs cycles de synchronisation de base de données pour éviter les pics d'script. Nettoyez tous les blips, accessoires et entités PNJ lorsque la ressource s'arrête pour empêcher les entités orphelines qui s'accumulent lors des redémarrages de la ressource. Testez ton système sous charge avec plusieurs restaurants en activité, plusieurs cuisiniers travaillant simultanément et un flux constant de commandes de clients pour identifier les goulots d'étranglement avant que tes joueurs ne les trouvent pour tu.

Partager cet article

Prêt à améliorer votre serveur ?

Découvrez nos scripts FiveM premium dans la boutique Agency Scripts ou rejoignez notre communauté Discord pour le support et les mises à jour.