Accueil › Documentation › Laboratoires personnalisés · origen_ilegalv2

Laboratoires personnalisés · origen_ilegalv2

origen_ilegalv2 fournit un Lab Process Runner générique qui gère tout le code répétitif d’un laboratoire de production : points d’interaction, markers, barres de progression, animations, validation côté serveur, consommation d’items et modificateurs d’améliorations. Pour ajouter un nouveau laboratoire de drogue, il te suffit d’écrire une table de configuration et d’appeler une fonction.


Fonctionnement

Le runner a deux côtés qui se répondent :

Côté Fichier Responsabilité
Client client/lab_process_runner.lua lib.points, markers, HelpText, barres de progression, animations, événements du cycle de vie
Serveur server/lab_process_runner.lua Validation des callbacks, vérification des items, consommation/remise des items, modificateurs d’améliorations, cooldowns

Les deux côtés s’enregistrent sous la même clé de type de laboratoire et communiquent via des callbacks ox_lib nommés automatiquement :

text
origen_gang:labs:{labType}:stage_{stageId}

Laboratoire minimal viable

1. Crée le fichier de configuration

luaconfig/lab_heroin.lua
Config.LabHeroin = {
    Enabled = true,
 
    -- Ordered production stages
    Stages = {
        { id = 'mix',      label_key = 'mixing',   help_key = 'mix',  done_key = 'mix_done',    timer = 10000 },
        { id = 'filter',   label_key = 'filtering', help_key = 'filter', done_key = 'filter_done', timer = 8000  },
        { id = 'bag',      label_key = 'bagging',  help_key = 'bag',  done_key = 'bag_done',    timer = 6000  },
    },
 
    ProductionCooldown = 600000,  -- 10 minutes between full cycles (ms)
 
    Interactions = {
        PointDistance    = 40.0,   -- lib.points render radius
        DrawDistance     = 8.0,    -- marker draw distance
        InteractDistance = 1.8,    -- HelpText / [E] distance
    },
 
    -- World coords for each stage (interior coords inside the lab bucket)
    Coords = {
        mix    = vector3(1006.09, -3200.59, -38.52),
        filter = vector3(1007.89, -3201.17, -38.99),
        bag    = vector3(1014.25, -3194.93, -38.99),
    },
 
    -- Progress bar durations per stage (ms)
    Timers = {
        mix    = 10000,
        filter = 8000,
        bag    = 6000,
    },
 
    -- Items consumed/delivered per stage
    -- inputs:   consumed when the stage starts
    -- outputs:  delivered when the stage completes
    -- requires: validated but NOT consumed (tools)
    Recipe = {
        mix = {
            inputs = {
                { item = 'opium_raw',  amount = 2 },
                { item = 'acetic_acid', amount = 1 },
            },
        },
        bag = {
            inputs  = { { item = 'empty_bag', amount = 3 } },
            outputs = { { item = 'heroin_bag', amount = 3 } },
        },
    },
}

L’ordre de Stages est l’ordre d’exécution obligatoire. Le runner l’impose : un joueur ne peut pas passer à l’étape N+1 sans avoir terminé l’étape N.

2. Enregistre-le côté serveur

luaserver/lab_heroin.lua
if not Config.LabHeroin or not Config.LabHeroin.Enabled then return end
 
LabProcessRunner.Register('heroin', Config.LabHeroin)
 
-- Optional: expose a reset export for external resources
exports('HeroinLabResetPlayerState', function(source)
    LabProcessRunner.ResetPlayerState('heroin', source)
end)

3. Enregistre-le côté client

luaclient/lab_heroin.lua
if not Config.LabHeroin or not Config.LabHeroin.Enabled then return end
 
LabProcessRunner.Register('heroin', Config.LabHeroin)

4. Ajoute le type de laboratoire à Config.LabTypes

Le runner ne crée pas le laboratoire dans la base de données : tu dois enregistrer un type de laboratoire pour que le panneau d’administration puisse en créer des instances :

luaconfig/labs.lua
Config.LabTypes = {
    -- ...existing types...
    heroin = {
        label = 'Heroin Lab',
        interior = {
            spawn  = vector4(997.17, -3200.64, -37.39, 270.0),
            laptop = vector4(1002.01, -3194.89, -38.99, 356.98),
        }
    },
}

5. Ajoute-le à fxmanifest.lua

luafxmanifest.lua
shared_scripts {
    -- ...
    'config/lab_heroin.lua',
}
 
server_scripts {
    -- ...
    'server/lab_heroin.lua',
}
 
client_scripts {
    -- ...
    'client/lab_heroin.lua',
}

6. Ajoute les clés de traduction

Pour chaque étape, il te faut trois clés de traduction (dans locales/translations/en.lua) :

lua
-- Progress bar label
['notify.heroin_mixing']      = 'Mixing...',
['notify.heroin_filtering']   = 'Filtering...',
['notify.heroin_bagging']     = 'Packaging...',
 
-- HelpText (shown when in range)
['notify.heroin_help_mix']    = 'Press [E] to mix chemicals',
['notify.heroin_help_filter'] = 'Press [E] to filter the mixture',
['notify.heroin_help_bag']    = 'Press [E] to bag the product',
 
-- Stage-done notifications
['notify.heroin_mix_done']    = 'Mixture ready',
['notify.heroin_filter_done'] = 'Filtration complete',
['notify.heroin_bag_done']    = 'Product packaged',  -- last stage receives output amount as arg
 
-- Error messages used by the runner
['notify.heroin_not_in_lab']             = 'You are not inside the lab',
['notify.heroin_wrong_lab_type']         = 'Wrong lab type',
['notify.heroin_on_cooldown']            = 'Wait before starting another cycle',
['notify.heroin_already_in_progress']    = 'Production already in progress',
['notify.heroin_wrong_stage']            = 'Complete the previous step first',
['notify.heroin_requires_basic_upgrade'] = 'Upgrade the lab before processing',

Référence complète de la configuration

Tableau Stages

Chaque entrée définit une étape de production :

Champ Type Obligatoire Description
id string ✅ Identifiant unique de l’étape. Utilisé dans les clés de Coords, Timers, Markers, Animations et Recipe
label_key string ✅ Suffixe de traduction pour la barre de progression : notify.{labType}_{label_key}
help_key string — Suffixe de traduction pour le HelpText : notify.{labType}_help_{help_key}. Par défaut, label_key
done_key string — Suffixe de traduction pour la notification de fin d’étape. Par défaut, {label_key}_done
timer number — Minuteur de l’étape en ms (à titre informatif : le runner utilise Timers[id] à l’exécution)

Table Recipe

Indexée par stage_id. Chaque entrée accepte :

Champ Type Description
inputs { item, amount }[] Consommés au début de l’étape
outputs { item, amount }[] Remis à la fin de l’étape
requires { item, amount }[] Vérifiés mais NON consommés (outils, licences)

Seules les étapes qui consomment ou produisent des items ont besoin d’une entrée. Les étapes sans entrée dans Recipe sont des transitions « libres ».

Table Markers

Indexée par stage_id. Tous les champs sont facultatifs : le runner se rabat sur un marker par défaut :

lua
Markers = {
    mix = {
        type          = 22,
        offset        = { x = 0.0, y = 0.0, z = 0.0 },
        scale         = { x = 0.25, y = 0.25, z = 0.25 },
        color         = { r = 0, g = 0, b = 0, a = 180 },
        bobUpAndDown  = true,
        faceCamera    = true,
        rotationOrder = 2,
        rotate        = false,
    },
},

Table Animations

Indexée par stage_id. Deux modes :

Simple (TaskPlayAnim) :

lua
mix = {
    networked = false,
    dict      = 'anim@amb@business@meth@meth_monitoring_cooking@',
    clip      = 'idle_a',
    flag      = 49,
    blendIn   = 4.0,
    blendOut  = -8.0,
    freeze    = false,
},

En réseau (NetworkCreateSynchronisedScene), avec des props :

lua
cook = {
    networked = true,
    dict      = 'anim@amb@business@meth@meth_monitoring_cooking@cooking@',
    clip      = 'chemical_pour_short_cooker',
    flag      = 49,
    blendIn   = 1.5,
    blendOut  = -4.0,
    freeze    = true,
    offset    = vector3(4.79, 2.13, -0.41),
    rotation  = vector3(0.0, 0.0, 0.0),
    objects   = {
        { hash = 'bkr_prop_meth_sacid',   clip = 'chemical_pour_short_sacid'   },
        { hash = 'bkr_prop_meth_ammonia', clip = 'chemical_pour_short_ammonia' },
    },
},

Flag RequiresUpgrade

Par défaut, la première étape de tout laboratoire basé sur le runner exige qu’une amélioration du module style soit débloquée dans cette instance du laboratoire. Pour désactiver cette restriction (utile pendant les tests ou pour des laboratoires en accès libre) :

lua
Config.LabHeroin = {
    RequiresUpgrade = false,  -- skip the upgrade gate
    -- ...
}

MaxDistPerStage

Distance maximale (en mètres), globale ou par étape, pour la validation de l’interaction côté serveur :

lua
-- Global: same distance for every stage
MaxDistPerStage = 4.0,
 
-- Per-stage override
MaxDistPerStage = {
    mix    = 3.0,
    filter = 5.0,
    bag    = 3.0,
},

Modificateurs d’améliorations

Quand un laboratoire a des améliorations du module style débloquées (depuis origen_gang_lab_upgrade_unlocks), le runner applique automatiquement :

Modificateur Effet Cumul
process_time_mult Multiplie tous les minuteurs des étapes (minimum 0.70, soit 30 % de réduction au maximum) Multiplicatif
output_bonus_pct % de chances de donner +1 unité sur la sortie de la dernière étape (maximum 25 %) Le maximum de toutes les variantes

Ils sont calculés côté serveur au début de chaque cycle et renvoyés au client sous la forme timers et modifiers dans la réponse du callback de la première étape.


Laboratoire de weed : flux spécial

Le laboratoire de weed (Config.LabWeed) n’utilise pas le runner générique. Il a son propre flux :

Étape Action Items
0 — Plantes Récolte 14 plantes (elles repoussent après PlantRespawnTime s) → wetcannabis ×1 chacune
1 — Séchage Place wetcannabis sur l’un des 4 points de séchage indépendants wetcannabis → drycannabis après DryWait ms
2 — Broyage Utilise le broyeur (nécessite weedgrinder, qui n’est pas consommé) drycannabis → grindedweed
3 — Ensachage Utilise la machine d’ensachage grindedweed + bluntwrap → blunt

Les étapes 1 à 3 sont indépendantes : il n’y a pas de séquence imposée entre elles. Il te suffit de l’item d’entrée correspondant.

Le temps des points de séchage est contrôlé côté serveur (horodatage ready_at) ; le minuteur du client est purement visuel.