117 lines
3.0 KiB
GDScript
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
|