godot.coroutines.awaitResourceLoad.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of godot-coroutine-library-release Show documentation
Show all versions of godot-coroutine-library-release Show documentation
Godot library extension allowing the use of coroutines in a Godot context.
The newest version!
package godot.coroutines
import godot.Error
import godot.Resource
import godot.ResourceLoader
import godot.ResourceLoader.CacheMode
import godot.core.variantArrayOf
import godot.global.GD
import godot.util.RealT
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.suspendCancellableCoroutine
import kotlin.coroutines.resume
import kotlin.coroutines.resumeWithException
/**
* Suspends the coroutine until a resource is loaded from the given path.
*
* @param path The path of the resource to be loaded.
* @param typeHint A hint about the type of resource being loaded.
* @param useSubThreads Specifies whether to use sub-threads for loading the resource.
* @param cacheMode The cache mode to be used while loading the resource.
* @param onProgress A callback function to track the progress of resource loading.
* @return The loaded resource, or null if there was an error.
*/
public suspend inline fun ResourceLoader.awaitLoad(
path: String,
typeHint: String = "",
useSubThreads: Boolean = false,
cacheMode: CacheMode = ResourceLoader.CacheMode.CACHE_MODE_REUSE,
crossinline onProgress: (RealT) -> Unit = {},
): Resource? {
// early return in case the resource is already loaded
if (this.hasCached(path)) {
return this.load(path)
}
val error = this.loadThreadedRequest(
path = path,
typeHint = typeHint,
useSubThreads = useSubThreads,
cacheMode = cacheMode,
)
if (error != Error.OK) {
GD.printErr("Could not trigger resource load. Got error: $error")
return null
}
return suspendCancellableCoroutine { continuation ->
CoroutineScope(Dispatchers.Default).launch {
var success = false
do {
val progress = variantArrayOf()
val status = awaitDeferred {
[email protected](
path = path,
progress = progress,
).also {
(progress.firstOrNull() as? RealT)?.let { onProgress(it) }
}
}
when (status) {
ResourceLoader.ThreadLoadStatus.THREAD_LOAD_LOADED -> success = true
ResourceLoader.ThreadLoadStatus.THREAD_LOAD_IN_PROGRESS -> {
// no op
}
ResourceLoader.ThreadLoadStatus.THREAD_LOAD_INVALID_RESOURCE,
ResourceLoader.ThreadLoadStatus.THREAD_LOAD_FAILED -> continuation.resumeWithException(
IllegalStateException("Failed to load resource: $status")
)
}
} while (status == ResourceLoader.ThreadLoadStatus.THREAD_LOAD_IN_PROGRESS)
if (success) {
continuation.resume([email protected](path))
}
}
}
}
/**
* Suspends the coroutine until a resource is loaded from the given path.
*
* @param path The path of the resource to be loaded.
* @param typeHint A hint about the type of resource being loaded.
* @param useSubThreads Specifies whether to use sub-threads for loading the resource.
* @param cacheMode The cache mode to be used while loading the resource.
* @param onProgress A callback function to track the progress of resource loading.
* @return The loaded resource, or null if there was an error.
*/
public suspend inline fun ResourceLoader.awaitLoadAs(
path: String,
typeHint: String = "",
useSubThreads: Boolean = false,
cacheMode: CacheMode = ResourceLoader.CacheMode.CACHE_MODE_REUSE,
crossinline onProgress: (RealT) -> Unit = {},
): R? {
@Suppress("UNCHECKED_CAST")
return this.awaitLoad(path, typeHint, useSubThreads, cacheMode, onProgress) as? R
}