Client audio
Client audio lets a client-side Lua resource play non-spatial interface sounds and positional world sounds. Audio handles belong to the resource that created them and cannot be controlled by another resource.
Supported files
The first release accepts Ogg containers containing Vorbis audio. Ogg Opus and other codecs are not accepted. Every sound must be declared as a join-time file in the same resource:
<?xml version="1.0" encoding="utf-8"?>
<scripts>
<script src="client.lua" type="client" cache="true" />
<file src="sounds/notification.ogg" download="join" />
<file src="sounds/forge.ogg" download="join" />
</scripts>
The runtime accepts only the exact relative path declared by the current resource. URLs, absolute paths, traversal with .., reparse-point escapes, undeclared files, and files owned by another resource are rejected. File size and SHA-256 are checked again against the signed resource catalog before decoding.
Audio functions
- playSound creates a non-spatial 2D sound.
- playSound3D creates a positional sound at world coordinates.
- stopSound stops a sound and invalidates its handle.
- setSoundVolume and getSoundVolume control linear volume.
- setSoundPaused and isSoundPaused control and inspect pause state.
- isSoundPlaying checks active playback.
- setSoundLooped changes looping.
- setSound3DPosition moves a positional source.
- setSound3DMinMaxDistance changes its attenuation range.
Playback quality and output device
2D playback preserves the source channel layout, so stereo material remains stereo. A positional source is downmixed to mono because it represents one point in the world. When source and output sample rates differ, the runtime converts once with the bundled libsamplerate 0.2.2 sinc converter using SRC_SINC_MEDIUM_QUALITY and bypasses miniaudio's pitch-oriented linear converter. Matching sample rates are not resampled.
Resource audio and voice playback use the normal Windows default playback device. The Windows communications-device selection is used only for voice microphone capture; it does not redirect or reduce the quality of 2D or 3D playback.
For 3D sound, volume remains full through minDistance, then fades linearly and is silent at and beyond maxDistance. Coordinates and distances use metres. The listener follows the local native player while at least one positional sound exists.
Local playback
local notification = playSound("sounds/notification.ogg", false, 0.65)
local forge = playSound3D(
"sounds/forge.ogg",
125.5, -48.0, 3.25,
true, 0.8,
2.0, 45.0
)
if forge then
setSound3DPosition(forge, 126.0, -48.0, 3.25)
setSound3DMinMaxDistance(forge, 2.0, 60.0)
end
Playing the same 3D sound for every player
Audio functions are client-side. To initiate a world sound authoritatively, the server sends a validated event to the client scripts. Using root as the target broadcasts the same reliable ordered event to every connected player.
Calculate the source position once on the server and send identical world coordinates to all clients. Do not recalculate the source from each receiving player's position.
server.lua
addCommandHandler("forgeaudio", function(playerId)
local position = getPlayerPosition(playerId)
if not position then
return
end
triggerClientEvent(
root,
"forgeAudio:play",
resourceRoot,
position.x + 4.0,
position.y,
position.z
)
end)
client.lua
local forgeSound = false
addEvent("forgeAudio:play", true)
addEventHandler("forgeAudio:play", resourceRoot, function(x, y, z)
if forgeSound then
stopSound(forgeSound)
end
forgeSound = playSound3D(
"sounds/forge.ogg",
x, y, z,
true, 0.8,
1.0, 30.0
)
end)
Each client creates its own local handle. Stopping, moving, pausing, or changing a shared sound therefore requires another server event broadcast to the same clients. Delivery is reliable and ordered, but playback start is not sample-accurate and can differ slightly due to network jitter.
Ownership and limits
- A resource can own at most 32 active sounds; the client runtime can own at most 128 in total.
- A handle can be controlled only by the resource that created it.
- Stopping a resource releases all sounds that it still owns.
- A stopped or finished handle must not be reused.
- Validation and playback failures are recorded in the client runtime log.