Configuration

8 min readUpdated 2 weeks ago

Overview

  • shared/config.lua: Core settings, features, the recycler definition, recipes, upgrades, durability, fuel, fixed stations
  • shared/data/item_models.lua: 3D prop mappings for the sinking animation
  • server/config_server.lua: Discord webhooks and rate limiting

The recipes and upgrades shipped in shared/config.lua are working examples. Replace them with the items your server uses.

General

shared/config.lua
1Config.Debug = false
2Config.Language = 'en'
3Config.Theme = 'default'
4Config.MaxRecyclersPerPlayer = 1
5Config.DuiResolution = { width = 1920, height = 1080 }
6Config.InteractionDistance = 3.0
7Config.PlacementDistance = 5.0
  • Debug: Console output for troubleshooting
  • Language: Locale code. See the locales/ folder.
  • Theme: Visual theme for the screen. The shipped theme is 'default'.
  • MaxRecyclersPerPlayer: Maximum player-placed recyclers per character
  • DuiResolution: Render resolution of the screen on the prop. 960x540 is lighter, 1920x1080 is sharper
  • InteractionDistance: Range in meters to interact with a placed machine
  • PlacementDistance: Maximum distance from the player a new machine can be placed

Placement Rules

shared/config.lua
1Config.PlacementRestriction = {
2    enabled = false,
3    radius = 25.0,
4    requiredProps = {},
5}
6
7Config.PickupCooldown = {
8    enabled = true,
9    seconds = 300,
10}
  • PlacementRestriction.enabled: When true, a recycler can only be placed within radius meters of one of the prop model hashes in requiredProps
  • PickupCooldown.enabled: Locks pickup for seconds after placing, blocking place-then-instant-pickup abuse

Feature Toggles

shared/config.lua
1Config.Features = {
2    bulkRecycling = true,
3    queueSystem = true,
4    fuelSystem = true,
5    breakdownAnimations = true,
6    ambientSounds = true,
7    propSinking = true,
8    lootReveal = true,
9    upgradeSystem = true,
10    durabilitySystem = true,
11}
  • bulkRecycling: Insert a stack of the same item in one action
  • queueSystem: Items queue when all slots are busy and auto-promote as slots free up
  • fuelSystem: Fuel is consumed while processing. When false, the fuel bar is hidden and refuel/consumption are disabled
  • breakdownAnimations: Particle effects during processing
  • ambientSounds: 3D loop sound through xsound while running
  • propSinking: Inserted item models sink into the slot as they process
  • lootReveal: Show the loot preview before collecting
  • upgradeSystem: Allow upgrade installation
  • durabilitySystem: Degradation, slowdown, malfunction and repair

The Recycler

shared/config.lua
1Config.Recycler = {
2    label = _L('recycler_label'),
3    item = 'recycler',
4    baseSlots = 3,
5    maxSlots = 6,
6    processSpeedMultiplier = 1.0,
7    spawnDistance = 50.0,
8    screenDistance = 10.0,
9}
  • label: Name shown in the UI and notifications
  • item: Inventory item used to place the recycler
  • baseSlots: Slots available before upgrades (each slot processes one item)
  • maxSlots: Absolute slot cap. Base plus a slot-expansion upgrade can never exceed this
  • processSpeedMultiplier: Base speed. 1.0 is normal, below 1.0 is faster
  • spawnDistance: Distance at which the prop streams in for nearby players
  • screenDistance: Distance at which the screen becomes visible
Recipe tier

Recipes can gate outputs and bonuses behind a recycler tier. The recycler runs at tier 1 by default. Add tier = 2 (or 3) to Config.Recycler to unlock higher-tier outputs and bonuses everywhere.

Fuel

Read only when Config.Features.fuelSystem = true.

shared/config.lua
1Config.Fuel = {
2    capacity = 100,
3    perMinute = 2,
4    items = {
5        ['industrial_battery'] = 25,
6        ['fuel_canister']      = 50,
7    },
8    mlFuel = {
9        enabled = true,
10        hintItems = {},
11        acceptedFuelTypes = { 'diesel' },
12        typeLabels = { ['diesel'] = 'Diesel', ['fuel'] = 'Gasoline' },
13        litersToUnits = 5,
14    },
15}
  • capacity: Tank size in units. The extra_tank upgrade raises it
  • perMinute: Units burned per minute of active processing
  • items: One-shot fuel items. ['item'] = units. The item is removed on use
  • mlFuel.enabled: Accept reusable jerrycans from ml_fuel. Any item carrying metadata.fuelAmount and metadata.fuelType is treated as a jerrycan: it is kept in the inventory and only emptied, never consumed
  • mlFuel.acceptedFuelTypes: Fuel types the machine accepts. Must match keys in ml_fuel Config.FuelTypes
  • mlFuel.typeLabels: UI label per fuel type
  • mlFuel.litersToUnits: How many recycler fuel units one liter of ml_fuel becomes

Recipes

The key is the input item. Each recipe defines the time and the possible outputs.

shared/config.lua
1Config.RecycleRecipes = {
2    ['broken_phone'] = {
3        baseTime = 20,
4        outputs = {
5            { item = 'glass',     min = 1, max = 2, chance = 100 },
6            { item = 'copper',    min = 1, max = 2, chance = 60 },
7            { item = 'microchip', min = 1, max = 1, chance = 15, tierRequired = 3 },
8        },
9        tierBonuses = {
10            [2] = { chanceBoost = 10, quantityBoost = 1 },
11            [3] = { chanceBoost = 25, quantityBoost = 2 },
12        },
13    },
14}
  • baseTime: Processing time in seconds. Effective time = baseTime * processSpeedMultiplier, then upgrade and durability modifiers
  • outputs: Possible results. Each has item, min/max quantity, and chance (0-100). Add tierRequired = 2 to gate an output behind a recycler tier
  • tierBonuses: Applied automatically by recycler tier. chanceBoost adds chance points to every output, quantityBoost adds to each output max

Rarity

Colors and labels for the loot preview.

shared/config.lua
1Config.Rarity = {
2    common    = { color = '#9ca3af', label = _L('rarity_common') },
3    uncommon  = { color = '#22c55e', label = _L('rarity_uncommon') },
4    rare      = { color = '#3b82f6', label = _L('rarity_rare') },
5    epic      = { color = '#a855f7', label = _L('rarity_epic') },
6    legendary = { color = '#f59e0b', label = _L('rarity_legendary') },
7}

Upgrades

shared/config.lua
1Config.MaxUpgradesPerRecycler = 3
2
3Config.Upgrades = {
4    ['turbo_motor']  = { label = _L('upgrade_turbo_motor'),  item = 'turbo_motor',  icon = 'turbo_motor',  effects = { processSpeedBonus = -0.20 } },
5    ['extra_tank']   = { label = _L('upgrade_extra_tank'),   item = 'extra_tank',   icon = 'extra_tank',   effects = { fuelCapacityBonus = 0.50 } },
6    ['silencer_kit'] = { label = _L('upgrade_silencer_kit'), item = 'silencer_kit', icon = 'silencer_kit', effects = { soundDistanceMultiplier = 0.40 } },
7    ['solar_panel']  = { label = _L('upgrade_solar_panel'),  item = 'solar_panel',  icon = 'solar_panel',  effects = { fuelRegenPerMinute = 1 } },
8}
  • MaxUpgradesPerRecycler: Upgrade slots per machine
  • effects.processSpeedBonus: Multiplier change to processing time. -0.20 is 20% faster
  • effects.fuelCapacityBonus: Fraction added to tank size. 0.50 is +50%
  • effects.soundDistanceMultiplier: Multiplies the ambient and zombie-noise radius. 0.40 is 60% quieter
  • effects.fuelRegenPerMinute: Passive fuel units generated per minute

Upgrades are consumed on install and returned to the player on removal, carrying their state. To make a slot-expansion module, add an upgrade with effects = { slotBonus = N }, give it an item, and the machine unlocks N extra slots up to maxSlots. The upgrade_slot_expansion label is already in the locale files.

Optional wear

Upgrades are permanent by default. Add a wear table to an upgrade definition to give it a durability curve that drains on use and auto-removes the module at zero:

lua
1['turbo_motor'] = {
2    label = _L('upgrade_turbo_motor'), item = 'turbo_motor', icon = 'turbo_motor',
3    effects = { processSpeedBonus = -0.20 },
4    wear = { enabled = true, startDurability = 100, degradePerProcess = 1 },
5}

Durability

shared/config.lua
1Config.Durability = {
2    degradePerProcess = 2,
3    slowdownThreshold = 50,
4    slowdownMultiplier = 1.20,
5    malfunctionThreshold = 25,
6    malfunctionChance = 15,
7    malfunctionCooldown = 600,
8    brokenThreshold = 0,
9}
  • degradePerProcess: Durability points lost per completed slot
  • slowdownThreshold: Below this percent, processing runs at slowdownMultiplier time
  • malfunctionThreshold: Below this percent, each process can jam
  • malfunctionChance: Malfunction probability (0-100)
  • malfunctionCooldown: Lockout in seconds after a malfunction
  • brokenThreshold: At this value the machine stops until repaired

Repair Items

shared/config.lua
1Config.RepairItems = {
2    ['repair_kit'] = { restore = 100, label = _L('repair_item_repair_kit') },
3    ['patch_kit']  = { restore = 50,  label = _L('repair_item_patch_kit') },
4    ['lubricant']  = { restore = 25,  label = _L('repair_item_lubricant') },
5}
  • restore: Durability points the item restores on use

Zombie Noise

shared/config.lua
1Config.ZombieNoise = {
2    enabled = false,
3    resourceName = 'ml_zombies',
4    defaultRadius = 50.0,
5    defaultDuration = 0,
6}
  • enabled: A running machine attracts zombies within defaultRadius
  • resourceName: Zombie resource to signal. The hook only fires if it is started
  • defaultDuration: 0 keeps the noise active until processing stops

The silencer_kit upgrade multiplies defaultRadius down through soundDistanceMultiplier.

Fixed Stations

Permanent recyclers you place in the world. Players cannot pick them up.

shared/config.lua
1Config.FixedStations = {
2    {
3        id = 'unique_station_id',
4        coords = vec3(0.0, 0.0, 0.0),
5        heading = 0.0,
6        infiniteFuel = false,
7        permanentUpgrades = { 'turbo_motor', 'silencer_kit' },
8    },
9}
  • id: Unique station id, stored in the database
  • infiniteFuel: When true, this station never runs out of fuel
  • permanentUpgrades: Upgrades installed for good. Players cannot remove them and the wear system ignores them

Permissions

shared/config.lua
1Config.DefaultPermissions = {
2    onlyOwnerCanUse = false,
3    onlyOwnerCanRemove = true,
4    onlyOwnerCanRefuel = false,
5    onlyOwnerCanUpgrade = false,
6}
  • Applies to every player-placed recycler. Fixed stations always allow public upgrade access so a town can share one machine

Discord Webhooks

server/config_server.lua
1ServerConfig.DiscordWebhook = ''
2ServerConfig.RecyclingWebhook = ''
3ServerConfig.PlacementWebhook = ''
4ServerConfig.ErrorWebhook = ''
5ServerConfig.ExploitsWebhook = ''
6ServerConfig.RateLimitCooldown = 1000
  • DiscordWebhook: Fallback webhook used by any channel left empty
  • RecyclingWebhook: Recycling started, collected, refueled, repaired, upgrade install/remove
  • PlacementWebhook: Recycler placed and picked up
  • ErrorWebhook: Database failures and rollback events
  • ExploitsWebhook: Rate-limit spam, payload type mismatches, distance and origin checks
  • RateLimitCooldown: Minimum milliseconds between actions per player

Set any webhook to false to disable that log entirely.