# (c) 2023-present Eroax # (c) 2023-present Yagich # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) extends Node class_name NodeDB_ ## Filepath used for referencing all [DeckNode] Files from. const BASE_NODE_PATH := "res://classes/deck/nodes/" ## Filepath where an Index of [NodeDB_.NodeDescriptor]s are saved to avoid reloading ## everything each run. ## @experimental const NODE_INDEX_CACHE_PATH := "user://nodes_index.json" ## Filepath where the the list of Favorite Nodes is stored. const FAVORITE_NODES_PATH := "user://favorite_nodes.json" ## [Array] used for storing all the "Favorite" Nodes that were set in the [AddNodeMenu] var favorite_nodes: Array[String] # Dictionary[node_type, NodeDescriptor] ## [Dictionary] filled with node_type, or [String] keys. Correlating to ## [NodeDB_.NodeDescriptor]'s. Essentially where all the nodes are loaded in for data reference. var nodes: Dictionary = {} ## Loads in all the [DeckNode]s from [member BASE_NODE_PATH]. Or if a working ## cache exists at [member NODE_INDEX_CACHE_PATH] that takes priority func _init() -> void: load_favorites() #if load_node_index(): #return create_descriptors(BASE_NODE_PATH) save_node_index() func create_descriptors(path: String) -> void: var dir := DirAccess.open(path) dir.list_dir_begin() var current_file := dir.get_next() while current_file != "": if dir.current_is_dir(): create_descriptors(path.path_join(current_file)) else: if current_file.ends_with(".gd"): var script_path := path.path_join(current_file) var node: DeckNode = load(script_path).new() as DeckNode var aliases: String = node.aliases.reduce( func(accum, el) -> void: accum += el , "") var descriptor := NodeDescriptor.new( script_path, node.name, node.node_type, node.description, aliases, path.get_slice("/", path.get_slice_count("/") - 1), node.appears_in_search, ) nodes[node.node_type] = descriptor current_file = dir.get_next() ## Helper Function that instances a [DeckNode] based off of it's [member DeckNode.node_type] func instance_node(type: String) -> DeckNode: if !nodes.has(type): return null return load(nodes[type]["script_path"]).new() ## Handles Saving the Index of all loaded nodes to [member NODE_INDEX_CACHE_PATH] func save_node_index() -> void: var d := {} for node_type in nodes: var nd: NodeDescriptor = nodes[node_type] as NodeDescriptor d[node_type] = nd.to_dictionary() var json := JSON.stringify(d, "\t") var f := FileAccess.open(NODE_INDEX_CACHE_PATH, FileAccess.WRITE) f.store_string(json) ## Loads the Node Index from [member NODE_INDEX_CACHE_PATH] adding all of the ## [NodeDB_.NodeDescriptor]s in it to the [member nodes] [Dictionary] func load_node_index() -> bool: var f := FileAccess.open(NODE_INDEX_CACHE_PATH, FileAccess.READ) if f == null: DeckHolder.logger.log_system("node index file does not exist", Logger.LogType.ERROR) return false var data: Dictionary = JSON.parse_string(f.get_as_text()) as Dictionary if data.is_empty(): DeckHolder.logger.log_system("node index file exists, but is empty", Logger.LogType.ERROR) return false for node_type in data: var nd_dict: Dictionary = data[node_type] var nd := NodeDescriptor.from_dictionary(nd_dict) nodes[node_type] = nd DeckHolder.logger.log_system("node index file exists, loaded") return true ## Sets a specific [member DeckNode.node_type] to be a "favorite" for use in ## [AddNodeMenu]. Then stores the updated list of favorites at [member FAVORITE_NODES_PATH] func set_node_favorite(node_type: String, favorite: bool) -> void: if (favorite && node_type in favorite_nodes) || (!favorite && !(node_type in favorite_nodes)): return if favorite: favorite_nodes.append(node_type) else: favorite_nodes.erase(node_type) var f := FileAccess.open(FAVORITE_NODES_PATH, FileAccess.WRITE) f.store_string(JSON.stringify(favorite_nodes, "\t")) ## Loads the list of Favorite [memeber DeckNode.node_type]s from [member FAVORITE_NODES_PATH] func load_favorites() -> void: var f := FileAccess.open(FAVORITE_NODES_PATH, FileAccess.READ) if !f: return var data: Array = JSON.parse_string(f.get_as_text()) favorite_nodes.clear() favorite_nodes.assign(data) ## Returns [code]true[/code] if the specified [member DeckNode.node_type] is marked Favorite ## by the user. func is_node_favorite(node_type: String) -> bool: return node_type in favorite_nodes ## Used for storing the shorthand data of a [DeckNode]. ## ## Allows for more simply storing [DeckNode]s properties without needing to ## keep an instance class NodeDescriptor: ## Default Name of the [DeckNode] type this is storing properties of. var name: String ## The [member DeckNode.node_type] of the [DeckNode] this is based off of. var type: String ## The description of the [DeckNode] reference [member DeckNode.description] var description: String ## The description of the [DeckNode] reference [member DeckNode.aliases] var aliases: String ## The description of the [DeckNode] reference [member DeckNode.category] var category: String ## The description of the [DeckNode] reference [member DeckNode.appears_in_search] var appears_in_search: bool ## Stores the path to this nodes [Script] in res:// for later instantiation. var script_path: String func _init( p_script_path: String, p_name: String, p_type: String, p_description: String, p_aliases: String, p_category: String, p_appears_in_search: bool, ) -> void: script_path = p_script_path name = p_name type = p_type description = p_description aliases = p_aliases category = p_category appears_in_search = p_appears_in_search ## Converts all the properties in this [NodeDB_.NodeDescriptor] to a [Dictionary]. Format - {propery : value} func to_dictionary() -> Dictionary: var d := { "name": name, "type": type, "description": description, "aliases": aliases, "script_path": script_path, "category": category, "appears_in_search": appears_in_search, } return d ## Creates a [NodeDB_.NodeDescriptor] from a given [Dictionary] of properties. static func from_dictionary(data: Dictionary) -> NodeDescriptor: var nd := NodeDescriptor.new( data.get("script_path", ""), data.get("name", ""), data.get("type", ""), data.get("description", ""), data.get("aliases", ""), data.get("category", ""), data.get("appears_in_search", false), ) return nd