127 lines
3.1 KiB
GDScript
127 lines
3.1 KiB
GDScript
class_name DeckManager
|
|
extends RefCounted
|
|
|
|
## DeckManager - Handles deck persistence (save/load)
|
|
|
|
const DECKS_DIR = "user://decks/"
|
|
|
|
|
|
## Save a deck to file
|
|
## Returns true on success
|
|
static func save_deck(deck: Deck, filename: String) -> bool:
|
|
# Ensure directory exists
|
|
DirAccess.make_dir_recursive_absolute(DECKS_DIR)
|
|
|
|
var path = DECKS_DIR + _sanitize_filename(filename) + ".json"
|
|
var file = FileAccess.open(path, FileAccess.WRITE)
|
|
if not file:
|
|
push_error("DeckManager: Failed to open file for writing: " + path)
|
|
return false
|
|
|
|
var data = deck.to_dict()
|
|
file.store_string(JSON.stringify(data, "\t"))
|
|
file.close()
|
|
return true
|
|
|
|
|
|
## Load a deck from file
|
|
## Returns null on failure
|
|
static func load_deck(filename: String) -> Deck:
|
|
var path = DECKS_DIR + _sanitize_filename(filename) + ".json"
|
|
|
|
if not FileAccess.file_exists(path):
|
|
push_error("DeckManager: File not found: " + path)
|
|
return null
|
|
|
|
var file = FileAccess.open(path, FileAccess.READ)
|
|
if not file:
|
|
push_error("DeckManager: Failed to open file for reading: " + path)
|
|
return null
|
|
|
|
var json_text = file.get_as_text()
|
|
file.close()
|
|
|
|
var json = JSON.new()
|
|
var error = json.parse(json_text)
|
|
if error != OK:
|
|
push_error("DeckManager: JSON parse error: " + json.get_error_message())
|
|
return null
|
|
|
|
var data = json.get_data()
|
|
if not data is Dictionary:
|
|
push_error("DeckManager: Invalid deck data format")
|
|
return null
|
|
|
|
var deck = Deck.new()
|
|
deck.from_dict(data)
|
|
return deck
|
|
|
|
|
|
## Delete a deck file
|
|
## Returns true on success
|
|
static func delete_deck(filename: String) -> bool:
|
|
var path = DECKS_DIR + _sanitize_filename(filename) + ".json"
|
|
|
|
if not FileAccess.file_exists(path):
|
|
return false
|
|
|
|
var dir = DirAccess.open(DECKS_DIR)
|
|
if dir:
|
|
return dir.remove(_sanitize_filename(filename) + ".json") == OK
|
|
return false
|
|
|
|
|
|
## List all saved decks
|
|
## Returns array of deck names (without .json extension)
|
|
static func list_decks() -> Array[String]:
|
|
var decks: Array[String] = []
|
|
|
|
# Ensure directory exists
|
|
DirAccess.make_dir_recursive_absolute(DECKS_DIR)
|
|
|
|
var dir = DirAccess.open(DECKS_DIR)
|
|
if not dir:
|
|
return decks
|
|
|
|
dir.list_dir_begin()
|
|
var filename = dir.get_next()
|
|
while filename != "":
|
|
if not dir.current_is_dir() and filename.ends_with(".json"):
|
|
decks.append(filename.trim_suffix(".json"))
|
|
filename = dir.get_next()
|
|
dir.list_dir_end()
|
|
|
|
decks.sort()
|
|
return decks
|
|
|
|
|
|
## Check if a deck exists
|
|
static func deck_exists(filename: String) -> bool:
|
|
var path = DECKS_DIR + _sanitize_filename(filename) + ".json"
|
|
return FileAccess.file_exists(path)
|
|
|
|
|
|
## Generate a unique deck name
|
|
static func generate_unique_name(base_name: String = "New Deck") -> String:
|
|
var name = base_name
|
|
var counter = 1
|
|
|
|
while deck_exists(name):
|
|
counter += 1
|
|
name = "%s %d" % [base_name, counter]
|
|
|
|
return name
|
|
|
|
|
|
## Sanitize filename to prevent path traversal
|
|
static func _sanitize_filename(filename: String) -> String:
|
|
# Remove path separators and dangerous characters
|
|
var sanitized = filename.replace("/", "_").replace("\\", "_")
|
|
sanitized = sanitized.replace("..", "_").replace(":", "_")
|
|
# Trim whitespace
|
|
sanitized = sanitized.strip_edges()
|
|
# Ensure not empty
|
|
if sanitized.is_empty():
|
|
sanitized = "deck"
|
|
return sanitized
|