241 lines
6.3 KiB
GDScript
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
|