brackeys-12/components/Data/data.gd
2024-09-08 13:34:41 -04:00

241 lines
6.3 KiB
GDScript

@icon("res://components/Data/book-marked.svg")
class_name DataType
extends Base
## Data handler to read in data from files
##
## A data handler that will read in data from txt files and other sources for
## use in various parts of the game. Reads both from the parts folder in the
## main game directory and the mods folder in the user folder to allow users to
## easily mod the game.
var _FILE_FUNCTIONS = {
"*.txt": _read_txt,
"*.png": _read_resource,
"*.png.import": _read_png_import,
"*.ogg": _read_resource,
"*.mp3": _read_resource,
"*.wav": _read_resource,
"*.gd": _read_script_resource,
}
var _FILE_LOCATION_OVERRIDES = {
"*.gd": "scripts",
"*.png.import": "images",
"*.png": "images",
"*.ogg": "audio",
"*.wav": "audio"
}
var data = {}
var components = {}
var location_overrides = {}
func _prespawned():
_information = {
"accent": "#a27155",
"log_category": "DATA",
"icon": "res://components/Data/book-marked.svg"
}
func _spawned():
reload_data()
## Reload the data object by pulling from available sources
func reload_data() -> void:
data = {} # Remove all old mod data
# Open part folder from project (Ignore if none) and if exists set mod data to it
var res_dir = DirAccess.open("res://")
if res_dir.dir_exists("parts"):
data = _read_directory("res://parts")
data = _merge_objects(location_overrides, data)
if res_dir.dir_exists("components"):
location_overrides = {}
components = _read_directory("res://components")
components = _merge_objects(location_overrides, components)
func _merge_objects(object1, object2):
var newObject = {}
for key in object1:
newObject[key] = object1[key]
for key in object2:
if(newObject.has(key)):
if(typeof(newObject[key]) == TYPE_STRING):
newObject[key] = object1[key]
elif(typeof(newObject[key]) == TYPE_OBJECT):
if newObject[key] is Texture:
newObject[key] = object1[key]
else:
newObject[key] = _merge_objects(object1[key], object2[key])
elif(typeof(newObject[key]) == TYPE_DICTIONARY):
newObject[key] = _merge_objects(object1[key], object2[key])
elif(typeof(newObject[key]) == TYPE_ARRAY):
newObject[key] = object1[key] + object2[key]
else:
newObject[key] = object2[key]
return newObject
func _read_directory(path) -> Dictionary:
var dir = DirAccess.open(path)
var local_data = {}
if not dir:
_warn("Could not read directory [%s]" % [path])
return {}
dir.list_dir_begin()
var file_name = dir.get_next()
while file_name != "":
if dir.current_is_dir():
var micro_data = _read_directory("%s/%s" % [path, file_name])
if micro_data:
local_data[file_name] = micro_data
else:
var file_handling = _get_file_handling(file_name)
if (file_handling):
var location_override = _get_location_override(file_name)
if location_override:
var micro_data = file_handling.call("%s/%s" % [path, file_name])
if not location_overrides.has(location_override):
location_overrides[location_override] = {}
location_overrides[location_override][file_name.split(".")[0]] = micro_data
else:
var micro_data = file_handling.call("%s/%s" % [path, file_name])
if micro_data:
local_data[file_name.split(".")[0]] = micro_data
file_name = dir.get_next()
_info("Read directory ♢%s" % [path])
return local_data
func _get_file_handling(file):
var split_file = file.split(".", true, 1)
for file_function in _FILE_FUNCTIONS:
if(file_function == file):
return _FILE_FUNCTIONS[file_function]
var split_file_function = file_function.split(".", true, 1)
if(split_file_function[0] == "*" and split_file_function[1] == split_file[1]):
return _FILE_FUNCTIONS[file_function]
return null
func _read_script_resource(path):
return load(path)
func _read_resource(path):
var song = load(path)
return song
func _read_png_import(path):
var image = load(path.rsplit(".", true, 1)[0])
return image
func _get_location_override(file):
var split_file = file.split(".", true, 1)
for location_override in _FILE_LOCATION_OVERRIDES:
if location_override == file:
return _FILE_LOCATION_OVERRIDES[location_override]
var split_file_function = location_override.split(".", true, 1)
if(split_file_function[0] == "*" and split_file_function[1] == split_file[1]):
return _FILE_LOCATION_OVERRIDES[location_override]
func _read_txt(path) -> Dictionary:
# Open file for reading
var file = FileAccess.open(path, FileAccess.READ)
var content = file.get_as_text()
var local_data = {}
# Separate into lines
var split_content = content.split("\n", false)
# Indentation
var indentation = 0
var indentation_levels = []
# Iterate over everything
for content_piece in split_content:
# Fix Indentation to actual content level
var actual_indentation = _count_indentation(content_piece)
while(actual_indentation < indentation):
indentation -= 1
indentation_levels.pop_back()
# Navigate to current indentation data
var micro_data = local_data
var previous_data = null
var i = 0
while i < indentation:
previous_data = micro_data
micro_data = micro_data[indentation_levels[i]]
i += 1
# Reading
if(content_piece.ends_with("[]")):
# Array handling
var trimmed_content = content_piece.strip_edges().trim_suffix("[]")
indentation += 1
indentation_levels.append(trimmed_content)
micro_data[trimmed_content] = {}
else:
var split_args = content_piece.split(":", true, 1)
if split_args.size() == 2:
# Dict Handling
var key = split_args[0].strip_edges()
var value = split_args[1].strip_edges()
if value.is_valid_int():
value = value.to_int()
micro_data[key] = value
elif split_args.size() == 1:
# Value Handling
var value = split_args[0].strip_edges()
if typeof(micro_data) == TYPE_DICTIONARY:
# TODO: FIX BELOW
if indentation_levels.size() == 0:
continue
if previous_data[indentation_levels[indentation_levels.size()-1]].keys().size() == 0:
previous_data[indentation_levels[indentation_levels.size()-1]] = [split_args[0].strip_edges()]
else:
pass
else:
previous_data[indentation_levels[indentation_levels.size()-1]] += [split_args[0].strip_edges()]
return local_data
func _count_indentation(string: String):
var tabs = 0
for character in string:
if(character == "\t"):
tabs += 1
else:
return tabs
return tabs