Files
modbison/scripts/studio/asset_cache_manager.gd

117 lines
3.0 KiB
GDScript

class_name AssetCacheManager
extends RefCounted
## Manages client-side disk caching of downloaded 3D model assets and collections.
## Caches assets locally under user://asset_cache/ to prevent duplicate network fetches.
const CACHE_DIR: String = "user://asset_cache"
static var _instance = null
static func get_instance():
if _instance == null:
var script := load("res://scripts/studio/asset_cache_manager.gd")
_instance = script.new()
return _instance
func _init() -> void:
_ensure_cache_dir()
func _ensure_cache_dir() -> void:
if not DirAccess.dir_exists_absolute(CACHE_DIR):
DirAccess.make_dir_recursive_absolute(CACHE_DIR)
func get_cache_path(asset_key: String) -> String:
var clean_key := asset_key.replace("/", "_").replace("\\", "_").replace(":", "_")
if not clean_key.ends_with(".glb") and not clean_key.ends_with(".gltf"):
clean_key += ".glb"
return "%s/%s" % [CACHE_DIR, clean_key]
func has_cached(asset_key: String) -> bool:
var p := get_cache_path(asset_key)
return FileAccess.file_exists(p)
func get_cached_path_if_exists(asset_key: String) -> String:
var p := get_cache_path(asset_key)
if FileAccess.file_exists(p):
return p
return ""
func store_asset(asset_key: String, data: PackedByteArray) -> String:
_ensure_cache_dir()
var path := get_cache_path(asset_key)
var fa := FileAccess.open(path, FileAccess.WRITE)
if fa != null:
fa.store_buffer(data)
fa.close()
return path
return ""
func read_asset(asset_key: String) -> PackedByteArray:
var path := get_cache_path(asset_key)
if not FileAccess.file_exists(path):
return PackedByteArray()
var fa := FileAccess.open(path, FileAccess.READ)
if fa != null:
var buf := fa.get_buffer(fa.get_length())
fa.close()
return buf
return PackedByteArray()
func load_model(asset_key: String) -> Node:
var path := get_cached_path_if_exists(asset_key)
if path == "":
return null
if path.ends_with(".glb") or path.ends_with(".gltf"):
var gltf := GLTFDocument.new()
var state := GLTFState.new()
var err := gltf.append_from_file(path, state)
if err == OK:
return gltf.generate_scene(state)
elif ResourceLoader.exists(path):
var res := load(path)
if res is PackedScene:
return (res as PackedScene).instantiate()
return null
func get_cached_items() -> Array[String]:
_ensure_cache_dir()
var items: Array[String] = []
var dir := DirAccess.open(CACHE_DIR)
if dir != null:
dir.list_dir_begin()
var file_name := dir.get_next()
while file_name != "":
if not dir.current_is_dir() and not file_name.begins_with("."):
items.append(file_name)
file_name = dir.get_next()
dir.list_dir_end()
return items
func clear_cache() -> int:
_ensure_cache_dir()
var count := 0
var dir := DirAccess.open(CACHE_DIR)
if dir != null:
dir.list_dir_begin()
var file_name := dir.get_next()
while file_name != "":
if not dir.current_is_dir():
DirAccess.remove_absolute("%s/%s" % [CACHE_DIR, file_name])
count += 1
file_name = dir.get_next()
dir.list_dir_end()
return count