- Added support for custom props in the sandbox, including loading, saving, and rendering. - Implemented `PropLibrary` for managing custom prop entries and scanning for `.prop` files. - Introduced `PropVisuals` for shared visual and collision representation of custom props. - Enhanced `StageSpawner` to handle spawning of custom props with layered visuals and collision hulls. - Created `MissingPropPlaceholder` to manage missing custom props during scene reloads. - Updated thumbnail generation to support custom props with unique keys based on file paths. - Added tests for custom prop lifecycle, authored visual values, and missing prop handling. - Refactored existing code to accommodate new prop functionalities and ensure backward compatibility.
95 lines
2.5 KiB
GDScript
95 lines
2.5 KiB
GDScript
class_name ThumbnailCache
|
|
extends RefCounted
|
|
|
|
const STICKMEN_DIR := "user://thumbnails/stickmen"
|
|
const PROP_DIR := "user://thumbnails/props"
|
|
const PROP_VERSION := 1
|
|
var _memory: Dictionary = {}
|
|
|
|
func get_texture(cache_path: String) -> Texture2D:
|
|
if _memory.has(cache_path):
|
|
return _memory[cache_path] as Texture2D
|
|
var texture: Texture2D = load_png(cache_path)
|
|
if texture != null:
|
|
_memory[cache_path] = texture
|
|
return texture
|
|
|
|
func store_texture(cache_path: String, texture: Texture2D) -> Error:
|
|
if texture == null:
|
|
return ERR_INVALID_PARAMETER
|
|
_memory[cache_path] = texture
|
|
return save_png(texture, cache_path)
|
|
|
|
func forget_memory(cache_path: String) -> void:
|
|
_memory.erase(cache_path)
|
|
|
|
func clear_memory() -> void:
|
|
_memory.clear()
|
|
|
|
|
|
func stickman_key(path: String) -> String:
|
|
return "%s_%d" % [path.get_file().get_basename(), FileAccess.get_modified_time(path)]
|
|
|
|
|
|
func stickman_png(key: String) -> String:
|
|
return STICKMEN_DIR + "/" + key + ".png"
|
|
|
|
|
|
func prop_png(id: String) -> String:
|
|
return PROP_DIR + "/" + id + "_v" + str(PROP_VERSION) + ".png"
|
|
|
|
|
|
func prop_file_key(path: String) -> String:
|
|
var canonical: String = path.simplify_path()
|
|
var digest: String = canonical.sha256_text().substr(0, 12)
|
|
return "file_%s_%d" % [digest, FileAccess.get_modified_time(path)]
|
|
|
|
|
|
func prop_file_png(path: String) -> String:
|
|
return PROP_DIR + "/" + prop_file_key(path) + ".png"
|
|
|
|
|
|
func load_png(png_path: String) -> Texture2D:
|
|
if _memory.has(png_path):
|
|
return _memory[png_path] as Texture2D
|
|
if not FileAccess.file_exists(png_path):
|
|
return null
|
|
var img := Image.load_from_file(png_path)
|
|
if img == null:
|
|
return null
|
|
var texture: Texture2D = ImageTexture.create_from_image(img)
|
|
_memory[png_path] = texture
|
|
return texture
|
|
|
|
|
|
func save_png(tex: Texture2D, png_path: String) -> Error:
|
|
if tex == null:
|
|
return ERR_INVALID_PARAMETER
|
|
var img := tex.get_image()
|
|
if img == null:
|
|
return ERR_CANT_CREATE
|
|
ensure_dir(png_path.get_base_dir())
|
|
_memory[png_path] = tex
|
|
return img.save_png(png_path)
|
|
|
|
|
|
func ensure_dir(dir: String) -> void:
|
|
DirAccess.make_dir_recursive_absolute(dir)
|
|
|
|
|
|
func clean_stale_stickmen(valid_keys: Dictionary) -> void:
|
|
if not DirAccess.dir_exists_absolute(STICKMEN_DIR):
|
|
return
|
|
var dir := DirAccess.open(STICKMEN_DIR)
|
|
if dir == null:
|
|
return
|
|
dir.list_dir_begin()
|
|
var fname := dir.get_next()
|
|
while fname != "":
|
|
if not dir.current_is_dir() and fname.ends_with(".png"):
|
|
var key := fname.trim_suffix(".png")
|
|
if not valid_keys.has(key):
|
|
DirAccess.remove_absolute(STICKMEN_DIR + "/" + fname)
|
|
fname = dir.get_next()
|
|
dir.list_dir_end()
|