Configuration
Everything a server owner touches lives in config/. Four files:
| File | What it holds |
|---|---|
settings.lua | Behaviour, keys, audio, access, limits, webhooks |
cabinets.lua | The carryable phonograph models |
spots.lua | Cabinets bolted to the map |
records.lua | The record catalogue |
All four stay editable in the escrowed package.
settings.lua
General
| Setting | Default | Meaning |
|---|---|---|
language | 'en' | Locale code; must match a file in locales/ (en, de, es, fr, it, pt) |
framework | 'auto' | 'auto' sniffs vorp_core → rsg-core → redem_roleplay, else standalone. Or pin one: 'vorp', 'rsg', 'redem', 'standalone' |
standalone.placeCommand | 'phonograph' | With no usable-item system, /phonograph starts placement instead |
debug.enabled | false | Verbose console tracing |
debug.log | {} | Silence one channel while debugging, e.g. { mixer = false } |
Notifications — bridge
| Setting | Default | Meaning |
|---|---|---|
notice | 'builtin' | 'builtin' = the resource's own themed toasts; 'framework' = hand off to your framework's notification; 'off' = silence |
noticeTime | 3500 | Toast duration in milliseconds |
Keys — keys
Control hashes. Defaults:
| Key | Default input | Used for |
|---|---|---|
tune | [R] | Open the deck panel |
pack | [Backspace] (hold) | Pick a placed cabinet up |
affirm | [R] (hold) | Placement: set it down |
abort | [Backspace] | Placement: put it away |
swingL / swingR | Arrow keys | Placement: rotate |
Placement — placing
| Setting | Default | Meaning |
|---|---|---|
reach | 1.3 | Metres in front of the player the ghost sits |
step | 1.5 | Degrees of rotation per frame while a swing key is held |
alpha | 160 | Ghost transparency (0–255) |
holdMs | 750 | How long the confirm key must be held |
World streaming — world
| Setting | Default | Meaning |
|---|---|---|
streamSpan | 40.0 | Metres at which cabinet props appear |
touchSpan | 2.0 | Metres at which the prompts light up |
scanMs | 500 | Slow world-scan interval, in ms |
Audio — audio
| Setting | Default | Meaning |
|---|---|---|
range | 15.0 | Metres at which a track fades to silence |
defaultVolume | 0.4 | 0–1, starting volume of a fresh track |
rolloff | 1.4 | Above 1 hugs the cabinet, below 1 carries further |
maxUrl | 300 | Longest link the server accepts |
crackle.enabled | true | Procedural vinyl-crackle bed, generated in the overlay — no file |
crackle.level | 0.35 | 0–1, relative to the track's own volume; 0 disables |
Access — access
| Setting | Default | Meaning |
|---|---|---|
ownerOnly | false | When true, a player-placed cabinet obeys only its owner (and staff) |
admins | {} | Character identifiers that count as staff everywhere |
aceFlag | 'rm_phonograph.admin' | Holders of this ace are staff too |
reachSpan | 4.0 | Server-side arm's length for every action |
packBlockSpan | 5.0 | Another player this close blocks a pickup |
Raw links — records.urlAccess
Who may paste a raw link into the panel. Catalogue records are always available to anyone the deck answers to — this gate is only for arbitrary URLs.
| Value | Meaning |
|---|---|
'everyone' | Any player the deck answers to |
'owners' (default) | The deck's owner; for map spots, whoever the spot's access names — so a public 'none' spot becomes records-only |
'staff' | Staff only |
Panel sections — panel
| Setting | Default | Meaning |
|---|---|---|
shelf | true | Show the record shelf. When false, record items also refuse to play — enforced server-side |
urlBox | true | Show the link box. When false, no link is accepted from anyone, staff included |
Limits — limits
| Setting | Default | Meaning |
|---|---|---|
queueCap | 8 | Tracks a deck's queue holds |
queuePerPlayer | 3 | How many of those one player may own |
playCooldownMs | 4000 | Between play/queue requests per player; staff exempt |
maxTrackMinutes | 0 | Auto-advance after this much played time — pauses don't count. 0 = off |
domains | {} | Allowed URL hosts; empty = any. e.g. { 'youtube.com', 'youtu.be' } — subdomains match automatically |
Discord webhooks — audit
Shipped off. Fill a url and flip enabled per channel:
| Channel | Fires on |
|---|---|
decks | A cabinet placed or packed up |
tracks | A track played or queued — includes who, the resolved title, and the video thumbnail |
Treat webhook URLs as secrets
Anyone holding the URL can post to that channel. Redact them before sharing a config.
cabinets.lua
The cabinets players can carry, keyed by name.
brass = {
item = 'phonograph', -- inventory item that plants one
label = 'Phonograph', -- shown on prompts and the panel
prop = 'p_phonograph01x',
carry = { -- how the prop rides the hand while carried
bone = 'XH_R_Hand01',
pos = { x = 0.30, y = -0.04, z = -0.31 },
rot = { x = -239.0, y = 13.0, z = 217.0 },
},
},The key is what the database stores
Renaming a cabinet orphans every deck already placed with it. Orphaned rows are kept and reported at boot, never deleted — but treat keys as permanent once players have placed cabinets.
Add more cabinets with different props and items; each needs its own usable item registered in your framework.
spots.lua
Cabinets bolted to the map. They exist without anyone placing them and cannot be packed up.
valentine_saloon = {
cabinet = 'brass',
access = 'none',
pos = vector3(-817.682, -1392.679, 43.345),
rot = vector3(0.0, 0.0, -111.448),
},access values:
| Value | Meaning |
|---|---|
'none' | Anyone may use the deck |
'ABCD1234...' | One character identifier |
{ 'saloon', 'bartender' } | A list of jobs |
This interacts with records.urlAccess
With the default urlAccess = 'owners', a 'none' spot is usable by everyone but accepts no raw links from non-staff — while a spot with an access list treats those people as its owners, and they can.
records.lua
The record catalogue. Each key is an inventory item; the deck shows the ones in the player's bags as sleeves on a shelf.
record_camptown = {
label = 'Camptown Races', -- on the sleeve and while playing
artist = 'Stephen Foster', -- optional second line
url = 'https://...', -- YouTube link or direct audio file
},- The URL is read from this table on the server — never from the client — so records cannot be forged.
- An entry with an empty
urlis skipped and named in the server console at boot. - To add your own: create the item in your framework, add an entry here, and drop a matching
<item_name>.pnginto your inventory's image folder.