11using System . Collections . Concurrent ;
22using Godot ;
33using STS2RitsuLib . Audio . Internal ;
4+ using FileAccess = Godot . FileAccess ;
45
56namespace STS2RitsuLib . Audio
67{
78 /// <summary>
8- /// Load loose audio files into the FMOD runtime (wav/ogg/mp3 per addon) from absolute filesystem paths.
9- /// Rejects <c>res://</c>, but resolves <c>user://</c> to an absolute filesystem path first. Tracks loaded paths so
10- /// you can unload deterministically.
9+ /// Load loose audio files into the FMOD runtime (wav/ogg/mp3 per addon). For <c>res://</c>, only paths that are
10+ /// still visible as raw files to <see cref="FileAccess" /> are accepted (e.g. Import dock "Keep File (No Import)
11+ /// ").
12+ /// Resolves <c>user://</c> to an absolute filesystem path. Tracks loaded paths so you can unload deterministically.
1113 /// </summary>
1214 public static class FmodStudioStreamingFiles
1315 {
@@ -81,7 +83,8 @@ public static bool TryPreloadAsStreamingMusic(string absolutePath)
8183 /// <summary>
8284 /// Returns a playable sound instance for the loose audio file at <paramref name="absolutePath" />, preloading as sound
8385 /// when needed.
84- /// Accepts absolute filesystem paths and resolves <c>user://</c> to an absolute filesystem path.
86+ /// Accepts <c>res://</c> only when the path is a raw file for <see cref="FileAccess" />, absolute paths, and
87+ /// <c>user://</c> (globalized).
8588 /// </summary>
8689 public static GodotObject ? TryCreateSoundInstance ( string absolutePath )
8790 {
@@ -103,7 +106,8 @@ public static bool TryPreloadAsStreamingMusic(string absolutePath)
103106
104107 /// <summary>
105108 /// Returns a streaming music instance, preloading as music when needed.
106- /// Accepts absolute filesystem paths and resolves <c>user://</c> to an absolute filesystem path.
109+ /// Accepts <c>res://</c> only when the path is a raw file for <see cref="FileAccess" />, absolute paths, and
110+ /// <c>user://</c> (globalized).
107111 /// </summary>
108112 public static GodotObject ? TryCreateStreamingMusicInstance ( string absolutePath )
109113 {
@@ -151,8 +155,11 @@ public static bool TryPlaySoundFile(string absolutePath, float volume = 1f, floa
151155 /// </summary>
152156 public static bool TryUnloadFile ( string absolutePath )
153157 {
154- return ! Loaded . TryRemove ( absolutePath , out _ ) ||
155- FmodStudioGateway . TryCall ( FmodStudioMethodNames . UnloadFile , absolutePath ) ;
158+ if ( ! TryResolveSupportedPath ( absolutePath , out var resolvedPath ) )
159+ return false ;
160+
161+ return ! Loaded . TryRemove ( resolvedPath , out _ ) ||
162+ FmodStudioGateway . TryCall ( FmodStudioMethodNames . UnloadFile , resolvedPath ) ;
156163 }
157164
158165 /// <summary>
@@ -173,16 +180,42 @@ private static bool TryResolveSupportedPath(string path, out string resolvedPath
173180 return false ;
174181 }
175182
176- if ( path . StartsWith ( "res ://" , StringComparison . OrdinalIgnoreCase ) )
183+ if ( path . StartsWith ( "user ://" , StringComparison . OrdinalIgnoreCase ) )
177184 {
178- RitsuLibFramework . Logger . Error ( $ "[Audio] FMOD file playback does not accept res:// paths: { path } ") ;
185+ resolvedPath = ProjectSettings . GlobalizePath ( path ) ;
186+ if ( ! Path . IsPathRooted ( resolvedPath ) )
187+ {
188+ RitsuLibFramework . Logger . Error ( $ "[Audio] FMOD file playback requires an absolute path: { path } ") ;
189+ return false ;
190+ }
191+
192+ if ( File . Exists ( resolvedPath ) ) return true ;
193+ RitsuLibFramework . Logger . Error ( $ "[Audio] FMOD file playback file not found: { resolvedPath } ") ;
179194 return false ;
180195 }
181196
182- resolvedPath = path . StartsWith ( "user://" , StringComparison . OrdinalIgnoreCase )
183- ? ProjectSettings . GlobalizePath ( path )
184- : path ;
197+ if ( path . StartsWith ( "res://" , StringComparison . OrdinalIgnoreCase ) )
198+ {
199+ if ( FileAccess . FileExists ( path ) )
200+ {
201+ resolvedPath = path ;
202+ return true ;
203+ }
204+
205+ if ( ResourceLoader . Exists ( path ) )
206+ {
207+ RitsuLibFramework . Logger . Warn (
208+ "[Audio] FMOD file playback: path resolves only as imported/packed resource, not as a raw file for FileAccess. " +
209+ "Avoid default import for assets you stream through FMOD: use the Import dock \" Keep File (No Import)\" " +
210+ "(or ship a loose file / FMOD Studio bank). Path: " + path ) ;
211+ return false ;
212+ }
213+
214+ RitsuLibFramework . Logger . Error ( $ "[Audio] FMOD file playback file not found: { path } ") ;
215+ return false ;
216+ }
185217
218+ resolvedPath = path ;
186219 if ( ! Path . IsPathRooted ( resolvedPath ) )
187220 {
188221 RitsuLibFramework . Logger . Error ( $ "[Audio] FMOD file playback requires an absolute path: { path } ") ;
0 commit comments