<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://g1r-mp.com/wiki/index.php?action=history&amp;feed=atom&amp;title=Game_audio</id>
	<title>Game audio - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://g1r-mp.com/wiki/index.php?action=history&amp;feed=atom&amp;title=Game_audio"/>
	<link rel="alternate" type="text/html" href="https://g1r-mp.com/wiki/index.php?title=Game_audio&amp;action=history"/>
	<updated>2026-10-01T17:28:02Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.46.0</generator>
	<entry>
		<id>https://g1r-mp.com/wiki/index.php?title=Game_audio&amp;diff=1190&amp;oldid=prev</id>
		<title>QCherry: Document upcoming 0.1.7 game audio: 11 client APIs, result event, limits and complete dialogue catalog; not a release</title>
		<link rel="alternate" type="text/html" href="https://g1r-mp.com/wiki/index.php?title=Game_audio&amp;diff=1190&amp;oldid=prev"/>
		<updated>2026-10-01T10:21:00Z</updated>

		<summary type="html">&lt;p&gt;Document upcoming 0.1.7 game audio: 11 client APIs, result event, limits and complete dialogue catalog; not a release&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;&amp;#039;&amp;#039;&amp;#039;Planned for update 0.1.7. These functions are not included in the public 0.1.6 release.&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
Game audio lets a client resource play built-in Gothic Remake sound effects, music and localized dialogue. Use catalog keys rather than filenames. The recordings remain in the player&amp;#039;s installed game; this API does not redistribute them.&lt;br /&gt;
&lt;br /&gt;
All functions on this page are &amp;#039;&amp;#039;&amp;#039;client-side&amp;#039;&amp;#039;&amp;#039; and use the exact lower-camel names shown below. Existing resource-file audio and voice chat are separate systems and remain unchanged.&lt;br /&gt;
&lt;br /&gt;
== API overview ==&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Function !! Purpose !! Immediate return&lt;br /&gt;
|-&lt;br /&gt;
| [[playSoundFromGame]] || Request listener-relative / 2D playback. || Sound handle or false.&lt;br /&gt;
|-&lt;br /&gt;
| [[playSound3DFromGame]] || Request playback at a world position. || Sound handle or false.&lt;br /&gt;
|-&lt;br /&gt;
| [[stopGameSound]] || Stop one owned sound, including a pending start. || Request ID or false.&lt;br /&gt;
|-&lt;br /&gt;
| [[setGameSoundVolume]] || Set an owned sound&amp;#039;s volume. || Request ID or false.&lt;br /&gt;
|-&lt;br /&gt;
| [[setGameSoundPaused]] || Pause or resume an owned sound. || Request ID or false.&lt;br /&gt;
|-&lt;br /&gt;
| [[setGameSound3DPosition]] || Move a source created with the 3D function. || Request ID or false.&lt;br /&gt;
|-&lt;br /&gt;
| [[setGameSound3DMinMaxDistance]] || Change that 3D source&amp;#039;s attenuation distances. || Request ID or false.&lt;br /&gt;
|-&lt;br /&gt;
| [[getGameSoundState]] || Read the latest accumulated state of an owned handle. || Table or false.&lt;br /&gt;
|-&lt;br /&gt;
| [[preloadGameSound]] || Request preparation and native capability information. || Request ID or false.&lt;br /&gt;
|-&lt;br /&gt;
| [[getGameSoundInfo]] || Read catalog metadata plus this resource&amp;#039;s last successful preload metadata. || Table or false.&lt;br /&gt;
|-&lt;br /&gt;
| [[getGameSoundCatalog]] || Search and paginate the built-in catalog. || Page table or false.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[onClientGameSoundResult]] reports asynchronous results and lifecycle changes to the owning resource.&lt;br /&gt;
&lt;br /&gt;
== Find a sound ==&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
local page = getGameSoundCatalog(&amp;quot;Diego&amp;quot;, &amp;quot;dialogue&amp;quot;, 0, 20)&lt;br /&gt;
if page then&lt;br /&gt;
    for _, item in ipairs(page.items) do&lt;br /&gt;
        outputDebugString(item.key .. &amp;quot; | &amp;quot; .. item.category .. &amp;quot; | &amp;quot; .. item.speaker)&lt;br /&gt;
    end&lt;br /&gt;
    outputDebugString(&amp;quot;Matching entries: &amp;quot; .. tostring(page.total))&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The defaults are an empty query, all categories, offset 0 and a page size of 50. Categories are &amp;lt;code&amp;gt;&amp;quot;&amp;quot;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;quot;sfx&amp;quot;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;quot;music&amp;quot;&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;&amp;quot;dialogue&amp;quot;&amp;lt;/code&amp;gt;. Search matches key/speaker, case-insensitively for ASCII names. A catalog entry identifies an allowed request; it does not guarantee that every game build or installed voice language contains a playable recording. The complete identifier list is in [[Game dialogue catalog]], not just the examples below.&lt;br /&gt;
&lt;br /&gt;
Examples of catalog keys:&lt;br /&gt;
* &amp;lt;code&amp;gt;event:/SFX/UI/SFX_UI_Jingle_LevelUp&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;event:/SFX/Objects/Fire/SFX_OBJ_Fire_Campfire_BurnLoop&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;event:/MUSIC/Locations/Explore/oldCamp/oldCampRing_day_explore&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;voice/INFO_DIEGO_BARRIERE_11_01&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Playback and asynchronous results ==&lt;br /&gt;
Install the result handler before requesting playback:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
addEventHandler(&amp;quot;onClientGameSoundResult&amp;quot;, resourceRoot,&lt;br /&gt;
    function(requestId, ok, reason, dataJson)&lt;br /&gt;
        local data = fromJSON(dataJson)&lt;br /&gt;
        if not ok then&lt;br /&gt;
            outputDebugString(&amp;quot;Game audio failed: &amp;quot; .. tostring(reason))&lt;br /&gt;
        end&lt;br /&gt;
        if type(data) == &amp;quot;table&amp;quot; and data.id and data.state then&lt;br /&gt;
            outputDebugString(&amp;quot;Sound &amp;quot; .. tostring(data.id) .. &amp;quot;: &amp;quot; .. data.state)&lt;br /&gt;
        end&lt;br /&gt;
    end)&lt;br /&gt;
&lt;br /&gt;
local sound = playSoundFromGame(&lt;br /&gt;
    &amp;quot;event:/SFX/UI/SFX_UI_Jingle_LevelUp&amp;quot;, {volume = 0.5})&lt;br /&gt;
if not sound then&lt;br /&gt;
    outputDebugString(&amp;quot;Game audio request was not accepted.&amp;quot;)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A returned handle means the request was accepted, &amp;#039;&amp;#039;&amp;#039;not&amp;#039;&amp;#039;&amp;#039; that the sound is already playing. The play request ID equals its sound handle. Later control calls return their own request IDs; the result&amp;#039;s &amp;lt;code&amp;gt;data.id&amp;lt;/code&amp;gt; identifies the affected sound. &amp;lt;code&amp;gt;requestId == 0&amp;lt;/code&amp;gt; identifies an unsolicited state/lifecycle notification.&lt;br /&gt;
&lt;br /&gt;
The event&amp;#039;s fourth argument is &amp;#039;&amp;#039;&amp;#039;JSON text&amp;#039;&amp;#039;&amp;#039;, not a Lua table. Decode it with [[fromJSON]] and check its type. Results are operation-dependent; do not assume every field is present.&lt;br /&gt;
&lt;br /&gt;
Typical states are &amp;lt;code&amp;gt;loading&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;starting&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;playing&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;paused&amp;lt;/code&amp;gt;, followed by &amp;lt;code&amp;gt;finished&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;stopped&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;failed&amp;lt;/code&amp;gt;. States may be skipped; short sounds can finish before the next script poll. The terminal states cannot be restarted: create a new handle to play again.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;confirmed&amp;lt;/code&amp;gt; is context-sensitive: a playing/finished observation confirms native playback was observed; a successful explicit stop may also set it to true to confirm the stop. Cancellation before startup can yield stopped with confirmed=false. It never proves that a player heard the sound. Check &amp;lt;code&amp;gt;state&amp;lt;/code&amp;gt; together with &amp;lt;code&amp;gt;confirmed&amp;lt;/code&amp;gt;, not the flag alone.&lt;br /&gt;
&lt;br /&gt;
== 3D placement and controls ==&lt;br /&gt;
Coordinates and distances are in &amp;#039;&amp;#039;&amp;#039;metres&amp;#039;&amp;#039;&amp;#039;, not Unreal centimetres. Supply a position in the same coordinate system as the multiplayer world-position API:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
local fire&lt;br /&gt;
&lt;br /&gt;
function startExampleFire(x, y, z)&lt;br /&gt;
    if fire then stopGameSound(fire) end&lt;br /&gt;
    fire = playSound3DFromGame(&lt;br /&gt;
        &amp;quot;event:/SFX/Objects/Fire/SFX_OBJ_Fire_Campfire_BurnLoop&amp;quot;,&lt;br /&gt;
        x, y, z, {volume = 0.6, minDistance = 1, maxDistance = 30})&lt;br /&gt;
    return fire&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function moveExampleFire(x, y, z)&lt;br /&gt;
    if not fire then return false end&lt;br /&gt;
    return setGameSound3DPosition(fire, x, y, z)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function stopExampleFire()&lt;br /&gt;
    if not fire then return false end&lt;br /&gt;
    local requestId = stopGameSound(fire)&lt;br /&gt;
    fire = nil&lt;br /&gt;
    return requestId&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After successful playback, the same resource can use &amp;lt;code&amp;gt;setGameSoundVolume(fire, 0.2)&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;setGameSoundPaused(fire, true)&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;setGameSoundPaused(fire, false)&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;setGameSound3DMinMaxDistance(fire, 1, 8)&amp;lt;/code&amp;gt;. Observe the asynchronous results rather than assuming that a truthy request ID means a completed control operation. Position and distance controls reject handles created with the non-3D function.&lt;br /&gt;
&lt;br /&gt;
Options may be omitted, nil or an empty table. Defaults are &amp;lt;code&amp;gt;{volume = 1, minDistance = 1, maxDistance = 30}&amp;lt;/code&amp;gt;. Unknown option names are rejected. Use actual numbers and booleans of the documented types; arbitrary wrong types can raise Lua argument errors rather than returning false.&lt;br /&gt;
&lt;br /&gt;
== Localized dialogue ==&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
local voice = playSoundFromGame(&amp;quot;voice/INFO_DIEGO_BARRIERE_11_01&amp;quot;, {volume = 0.8})&lt;br /&gt;
if not voice then&lt;br /&gt;
    outputDebugString(&amp;quot;Dialogue request was rejected.&amp;quot;)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The game&amp;#039;s selected voice language determines the recording. Playing a line does not run a conversation graph, quest or subtitle scene. There is no language-override parameter and no substitution of another character&amp;#039;s line or an alternate language by this API. Missing recordings or unavailable native facilities produce explicit errors.&lt;br /&gt;
&lt;br /&gt;
The same voice key can be used with [[playSound3DFromGame]] for a world-positioned voice. The current implementation uses the game&amp;#039;s own archive-aware audio loading rather than accepting a raw recording path.&lt;br /&gt;
&lt;br /&gt;
== Preloading and metadata ==&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
local key = &amp;quot;event:/SFX/Objects/Fire/SFX_OBJ_Fire_Campfire_BurnLoop&amp;quot;&lt;br /&gt;
local requestId = preloadGameSound(key)&lt;br /&gt;
-- Wait for this requestId in onClientGameSoundResult.&lt;br /&gt;
-- After successful completion, getGameSoundInfo(key) includes native metadata.&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Catalog metadata initially includes &amp;lt;code&amp;gt;key&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;category&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;speaker&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;capabilitiesKnown=false&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;verifiedInGame=false&amp;lt;/code&amp;gt;. Successful preload enriches this resource&amp;#039;s cached info with fields such as &amp;lt;code&amp;gt;authoredSpatial&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;oneShot&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;loopMode&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;eventSamplesPreloaded&amp;lt;/code&amp;gt;. Playback alone does not populate that info cache. &amp;lt;code&amp;gt;verifiedInGame&amp;lt;/code&amp;gt; remains false; it is not a per-player listening test result.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Voice preload is a request, not an independently confirmed recording preload.&amp;#039;&amp;#039;&amp;#039; A successful result can contain &amp;lt;code&amp;gt;voicePreloadRequested=true&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;voicePreloadConfirmed=false&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;recordingResolved=true&amp;lt;/code&amp;gt;. Loaded event samples or a resolved recording do not prove that the voice PCM is ready or audible. Do not turn these flags into a claim that a dialogue has played.&lt;br /&gt;
&lt;br /&gt;
== Authored behavior and music ==&lt;br /&gt;
* Looping, sustain and musical layers come from the authored event. There is no forced-loop option; &amp;lt;code&amp;gt;oneShot=false&amp;lt;/code&amp;gt; does not guarantee a simple repeating loop.&lt;br /&gt;
* Non-3D playback of an authored spatial sound uses a source following the local camera, with per-instance attenuation. The reported mode is &amp;lt;code&amp;gt;listener-relative&amp;lt;/code&amp;gt;. Truly 2D events report &amp;lt;code&amp;gt;authored-2d&amp;lt;/code&amp;gt;; world-positioned playback reports &amp;lt;code&amp;gt;world-3d&amp;lt;/code&amp;gt;.&lt;br /&gt;
* A 3D request for an authored 2D event fails with &amp;lt;code&amp;gt;event-is-2d&amp;lt;/code&amp;gt;. Metadata and errors should be checked for each chosen key.&lt;br /&gt;
* This API does not stop the game&amp;#039;s existing ambient music or change its global mixer/listener settings. Custom music can overlap native music. Game/user audio settings can affect what is heard.&lt;br /&gt;
* There are no bus/VCA, global event, arbitrary programmer-sound, raw pointer, URL or filesystem-path controls.&lt;br /&gt;
&lt;br /&gt;
== Multiplayer and lifetime ==&lt;br /&gt;
Playback is &amp;#039;&amp;#039;&amp;#039;local to each client&amp;#039;&amp;#039;&amp;#039;. A server resource may select recipients with [[triggerClientEvent]], and a matching client handler can call these functions. There is no automatic broadcast, late-join replay or sample-accurate cross-client synchronization. Maintain desired persistent ambient sounds in your own resource and create them for newly joined clients when their world is ready.&lt;br /&gt;
&lt;br /&gt;
Handles belong to the client resource that created them. Another resource cannot query/control them. Do not send a handle to another player or store it in a database as a persistent ID. Handles are not reused during the client runtime&amp;#039;s lifetime, but become invalid after resource/lifecycle cleanup; older terminal records can be evicted.&lt;br /&gt;
&lt;br /&gt;
Resource stop, disconnect, world replacement or loss of the native owner heartbeat clean up only the instances/preloads owned by this API. A world-reset notification has requestId=0, ok=false, reason=&amp;lt;code&amp;gt;world-reset&amp;lt;/code&amp;gt; and an empty data object. Clear your script&amp;#039;s saved handles in that case. Native NPC dialogue, other resources&amp;#039; file audio and voice chat are not globally stopped.&lt;br /&gt;
&lt;br /&gt;
== Limits and error handling ==&lt;br /&gt;
See [[Scripting limits#Game audio (upcoming 0.1.7)|Game audio limits]] for numeric validation, capacity and timeouts. Cold loading can take time; preload a small useful selection instead of the entire catalog, and do not retry every frame.&lt;br /&gt;
&lt;br /&gt;
Immediate false means the request was not accepted: for example an unknown key, invalid numeric range, foreign/ended handle, unavailable gameplay, or full capacity. No asynchronous completion is promised for a rejected request. Accepted requests can still fail later. Examples include &amp;lt;code&amp;gt;event-is-2d&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;preload-cache-full&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;native-queue-full&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;native-loading-timeout&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;native-timeout&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;localized-recording-path-missing&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;playback-not-observed&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;listener-lost&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;sound-not-owned-or-ended&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Log the reason and available result fields, stop retry loops, and provide a fallback in your resource. Do not infer acoustic success from request acceptance or from the existence of a catalog entry.&lt;br /&gt;
&lt;br /&gt;
[[Category:Lua API]]&lt;br /&gt;
[[Category:Lua Examples]]&lt;/div&gt;</summary>
		<author><name>QCherry</name></author>
	</entry>
</feed>