crafting
Last updated on
A shared crafting service — other modules register benches with recipes, players hand over materials and collect the output when the timer ends.
Workbenches for other modules. No recipes of its own: a module such as gunsmith registers a bench with its recipes. At a bench the player sees what can be made, what each recipe needs and what is already cooking. Ordering takes the materials (and an optional fee) at once; the item is ready after the recipe's time, even across a server restart, and the player comes back to collect it. Use it for "spend items, wait, receive an item".
| Side | both |
| Requires | inventory, character (hard) |
| Optional | menu (the bench screen), progress (the handover bar) |
| Contract | crafting v1 — server, client |
| Config | config/crafting.lua (shared) |
| Data | opx77_crafting_orders |
How a bench works
- Each character has its own queue per bench, up to the bench's
queueorders. - Sequential: a new order starts when the previous one is ready.
- Ordering checks gate, reach, queue space, materials and money, then removes the materials, then takes the fee. If a later step fails, earlier ones are given back.
- Ready times use the database clock (
ready_at): an order keeps cooking while the server is down. - Collecting checks the bag can carry the output first. The order is deleted, then the item given; if it cannot be given, the order is put back on the shelf.
- A bench with a
positionis reach-checked on the server (itsreachplusREACH_SLACK); without one it can be used from anywhere. This covers the gunsmith bench. - Refunds and output go to the character, not the connection. The citizen id is pinned and checked again after each yield; materials and the output go to that character's bag (loaded if absent) and the fee comes back through
AddMoneyOffline, so a player who left or switched character mid-order loses nothing and pays nobody else. A refund that still fails is logged. - A placement carries a token (column
token, added to an existingopx77_crafting_ordersbyOPX.Schema.AddColumns). When a placement answers a failure, the order is looked up by its token before anything is refunded: found, the order stands; absent, everything is refunded; unknown after three tries, nothing is refunded and the log names the token and the amounts to settle by hand. - No screen, order or collect from the floor (
downed). A refusal names back the bench key only when it could name a bench. - Order and collect are audited (
crafting.order,crafting.collect).
Bench definition
The table passed to RegisterBench. Lower-case keys.
crafting.RegisterBench('mymodule:bench', {
owner = 'mymodule',
label = 'Ammo bench',
position = { x = -1520.2, y = 891.4, z = 42.1, bucket = 0 },
canUse = function(player, recipeKey) return true end,
recipes = {
{ KEY = 'handgun_rounds', ICON = 'ammo', OUTPUT = 'ammo_handgun', COUNT = 30,
SECONDS = 120, INPUTS = { scrap_metal = 2 }, PRICE = 40, MONEY = 'EDDIES' },
},
})| Field | Required | Effect |
|---|---|---|
owner | yes | Name of the registering module. Used by UnregisterBenches. |
label | no | Menu title. Default: the bench key. Max 64 bytes. |
position | no | { x, y, z, bucket? }. Turns on the server reach check. |
reach | no | Metres, above 0 and at most MAX_REACH. Default REACH. |
queue | no | 1 to MAX_QUEUE. Default QUEUE. |
canUse | no | function(player, recipeKey) → allowed, code?. Called with recipeKey = nil for the bench, then once per recipe. A code shows crafting.<code>. A raise refuses with not_for_you. |
recipes | yes | List of recipes, at most MAX_RECIPES. |
Bench and recipe keys: letters, digits, _, -, ., :, up to 64.
Recipe fields
Upper-case keys, as in a config file.
| Field | Required | Effect |
|---|---|---|
KEY | yes | Recipe key, unique on the bench. |
OUTPUT | yes | Item given. Must be in the inventory catalogue. |
COUNT | no | Units given, 1 to MAX_YIELD. Default 1. |
SECONDS | yes | Cooking time, MIN_SECONDS to MAX_SECONDS. |
INPUTS | yes | { item = units }, 1 to MAX_INPUTS items, each in the catalogue. |
PRICE | no | Fee in whole units. Default 0. |
MONEY | if PRICE > 0 | Money type the fee is taken from. |
LABEL | no | Menu label. Default: the output's label. |
ICON | no | A name from OPX.Glyphs. |
A recipe that breaks a rule is dropped with a boot warning. A bench left with no recipe is refused.
Configuration
config/crafting.lua sets OPX.Config.MODULES.crafting. Shared. Limits on what a registering module may ask for; recipes live in the consumer's own config.
Refusal codes
The toast key is crafting.<code>. A canUse gate may answer its own codes; the registering module must add crafting.<code> to its locales (gunsmith does).
| Code | Meaning |
|---|---|
no_such_bench | No bench with that key. |
no_such_recipe | The bench has no such recipe (or no longer has it). |
not_for_you | The canUse gate refused, or raised. |
too_far | Out of reach, or another bucket. |
no_position | The server cannot read the player's position. |
no_character | No character loaded. |
short | Not enough materials. |
cannot_pay | Fee could not be paid. |
queue_full | The queue is full. The cap is checked in the same statement that writes the order, so two orders placed at once cannot pass it; a refused order gives back its materials and fee. |
no_such_order | Not one of this character's orders. |
not_ready | Still cooking. |
no_room | The bag cannot carry the output. |
too_fast | Rate limit. |
downed | The player is down (Not from the floor.). |
unavailable | Database error. |