You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
455 lines
14 KiB
455 lines
14 KiB
tool |
|
class_name DialogicResources |
|
|
|
## This class is used by the DialogicEditor to access the resources files |
|
## For example by the Editors (Timeline, Character, Theme), the MasterTree and the EventParts |
|
|
|
## It is also used by the DialogicUtil class |
|
|
|
const RESOURCES_DIR: String = "res://dialogic" # Readonly, used for static data |
|
const WORKING_DIR: String = "user://dialogic" # Readwrite, used for saves |
|
|
|
|
|
## ***************************************************************************** |
|
## BASIC JSON FUNCTION |
|
## ***************************************************************************** |
|
static func load_json(path: String, default: Dictionary={}) -> Dictionary: |
|
# An easy function to load json files and handle common errors. |
|
var file := File.new() |
|
if file.open(path, File.READ) != OK: |
|
file.close() |
|
return default |
|
var data_text: String = file.get_as_text() |
|
file.close() |
|
if data_text.empty(): |
|
return default |
|
var data_parse: JSONParseResult = JSON.parse(data_text) |
|
if data_parse.error != OK: |
|
return default |
|
|
|
var final_data = data_parse.result |
|
if typeof(final_data) == TYPE_DICTIONARY: |
|
return final_data |
|
|
|
# If everything else fails |
|
return default |
|
|
|
|
|
static func set_json(path: String, data: Dictionary): |
|
var file = File.new() |
|
var err = file.open(path, File.WRITE) |
|
if err == OK: |
|
file.store_line(JSON.print(data, '\t', true)) |
|
file.close() |
|
return err |
|
|
|
|
|
## ***************************************************************************** |
|
## INITIALIZATION |
|
## ***************************************************************************** |
|
static func init_dialogic_files() -> void: |
|
# This functions makes sure that the needed files and folders |
|
# exists when the plugin is loaded. If they don't, we create |
|
# them. |
|
# WARNING: only call while in the editor |
|
var directory = Directory.new() |
|
var paths = get_working_directories() |
|
var files = get_config_files_paths() |
|
# Create directories |
|
for dir in paths: |
|
if not directory.dir_exists(paths[dir]): |
|
directory.make_dir_recursive(paths[dir]) |
|
if dir == 'THEME_DIR': |
|
directory.copy('res://addons/dialogic/Editor/ThemeEditor/default-theme.cfg', str(paths[dir], '/default-theme.cfg')) |
|
# Create empty files |
|
for f in files: |
|
if not directory.file_exists(files[f]): |
|
create_empty_file(files[f]) |
|
|
|
|
|
static func get_working_directories() -> Dictionary: |
|
return { |
|
'RESOURCES_DIR': RESOURCES_DIR, |
|
'WORKING_DIR': WORKING_DIR, |
|
'TIMELINE_DIR': RESOURCES_DIR + "/timelines", |
|
'THEME_DIR': RESOURCES_DIR + "/themes", |
|
'CHAR_DIR': RESOURCES_DIR + "/characters", |
|
'CUSTOM_EVENTS_DIR': RESOURCES_DIR + "/custom-events" |
|
} |
|
|
|
|
|
static func get_config_files_paths() -> Dictionary: |
|
return { |
|
'SETTINGS_FILE': RESOURCES_DIR + "/settings.cfg", |
|
'DEFAULT_DEFINITIONS_FILE': RESOURCES_DIR + "/definitions.json", |
|
'FOLDER_STRUCTURE_FILE': RESOURCES_DIR + "/folder_structure.json", |
|
'DEFINITIONS_DEFAULT_SAVE': WORKING_DIR + "/definitions_default_save.json", |
|
'STATE_DEFAULT_SAVE': WORKING_DIR + "/state_default_save.json" |
|
} |
|
|
|
|
|
## ***************************************************************************** |
|
## BASIC FILE FUNCTION |
|
## ***************************************************************************** |
|
static func get_path(name: String, extra: String ='') -> String: |
|
var paths: Dictionary = get_working_directories() |
|
if extra != '': |
|
return paths[name] + '/' + extra |
|
else: |
|
return paths[name] |
|
|
|
|
|
static func get_filename_from_path(path: String, extension = false) -> String: |
|
var file_name: String = path.split('/')[-1] |
|
if extension == false: |
|
file_name = file_name.split('.')[0] |
|
return file_name |
|
|
|
|
|
static func listdir(path: String) -> Array: |
|
# https://docs.godotengine.org/en/stable/classes/class_directory.html#description |
|
var files: Array = [] |
|
var dir := Directory.new() |
|
var err = dir.open(path) |
|
if err == OK: |
|
dir.list_dir_begin() |
|
var file_name = dir.get_next() |
|
while file_name != "": |
|
if not dir.current_is_dir() and not file_name.begins_with("."): |
|
files.append(file_name) |
|
file_name = dir.get_next() |
|
dir.list_dir_end() |
|
else: |
|
print("[Dialogic] Error while accessing path " + path + " - Error: " + str(err)) |
|
return files |
|
|
|
|
|
static func create_empty_file(path): |
|
var file = File.new() |
|
file.open(path, File.WRITE) |
|
file.store_string('') |
|
file.close() |
|
|
|
|
|
static func remove_file(path: String): |
|
var dir = Directory.new() |
|
var _err = dir.remove(path) |
|
|
|
if _err != OK: |
|
print("[D] There was an error when deleting file at {filepath}. Error: {error}".format( |
|
{"filepath":path,"error":_err} |
|
)) |
|
|
|
|
|
static func copy_file(path_from, path_to): |
|
if (path_from == ''): |
|
push_error("[Dialogic] Could not copy empty filename") |
|
return ERR_FILE_BAD_PATH |
|
|
|
if (path_to == ''): |
|
push_error("[Dialogic] Could not copy to empty filename") |
|
return ERR_FILE_BAD_PATH |
|
|
|
var dir = Directory.new() |
|
if (not dir.file_exists(path_from)): |
|
push_error("[Dialogic] Could not copy file %s, File does not exists" % [ path_from ]) |
|
return ERR_FILE_NOT_FOUND |
|
|
|
if (dir.file_exists(path_to)): |
|
push_error("[Dialogic] Could not copy file to %s, file already exists" % [ path_to ]) |
|
return ERR_ALREADY_EXISTS |
|
|
|
var error = dir.copy(path_from, path_to) |
|
if (error): |
|
push_error("[Dialogic] Error while copying %s to %s" % [ path_from, path_to ]) |
|
push_error(error) |
|
return error |
|
|
|
return OK |
|
pass |
|
|
|
|
|
## ***************************************************************************** |
|
## CONFIG |
|
## ***************************************************************************** |
|
static func get_config(id: String) -> ConfigFile: |
|
var paths := get_config_files_paths() |
|
var config := ConfigFile.new() |
|
if id in paths.keys(): |
|
var err = config.load(paths[id]) |
|
if err != OK: |
|
print("[Dialogic] Error while opening config file " + paths[id] + ". Error: " + str(err)) |
|
return config |
|
|
|
|
|
## ***************************************************************************** |
|
## TIMELINES |
|
## ***************************************************************************** |
|
# Can only be edited in the editor |
|
|
|
static func get_timeline_json(path: String): |
|
return load_json(get_path('TIMELINE_DIR', path)) |
|
|
|
|
|
static func set_timeline(timeline: Dictionary): |
|
# WARNING: For use in the editor only |
|
set_json(get_path('TIMELINE_DIR', timeline['metadata']['file']), timeline) |
|
|
|
|
|
static func delete_timeline(filename: String): |
|
# WARNING: For use in the editor only |
|
remove_file(get_path('TIMELINE_DIR', filename)) |
|
|
|
|
|
## ***************************************************************************** |
|
## CHARACTERS |
|
## ***************************************************************************** |
|
# Can only be edited in the editor |
|
|
|
static func get_character_json(path: String): |
|
return load_json(get_path('CHAR_DIR', path)) |
|
|
|
|
|
static func set_character(character: Dictionary): |
|
# WARNING: For use in the editor only |
|
set_json(get_path('CHAR_DIR', character['id']), character) |
|
|
|
|
|
static func delete_character(filename: String): |
|
# WARNING: For use in the editor only |
|
remove_file(get_path('CHAR_DIR', filename)) |
|
|
|
|
|
## ***************************************************************************** |
|
## THEMES |
|
## ***************************************************************************** |
|
# Can only be edited in the editor |
|
|
|
static func get_theme_config(filename: String): |
|
var config = ConfigFile.new() |
|
var path |
|
if filename.begins_with('res://'): |
|
path = filename |
|
else: |
|
path = get_path('THEME_DIR', filename) |
|
var err = config.load(path) |
|
if err == OK: |
|
return config |
|
|
|
|
|
static func set_theme_value(filename, section, key, value): |
|
# WARNING: For use in the editor only |
|
var config = get_theme_config(filename) |
|
config.set_value(section, key, value) |
|
config.save(get_path('THEME_DIR', filename)) |
|
|
|
|
|
static func add_theme(filename: String): |
|
create_empty_file(get_path('THEME_DIR', filename)) |
|
|
|
|
|
static func delete_theme(filename: String): |
|
remove_file(get_path('THEME_DIR', filename)) |
|
|
|
|
|
static func duplicate_theme(from_filename: String, to_filename: String): |
|
copy_file(get_path('THEME_DIR', from_filename), get_path('THEME_DIR', to_filename)) |
|
|
|
## ***************************************************************************** |
|
## SETTINGS |
|
## ***************************************************************************** |
|
# Can only be edited in the editor |
|
|
|
|
|
static func get_settings_config() -> ConfigFile: |
|
return get_config("SETTINGS_FILE") |
|
|
|
|
|
static func set_settings_value(section: String, key: String, value): |
|
var config = get_settings_config() |
|
config.set_value(section, key, value) |
|
config.save(get_config_files_paths()['SETTINGS_FILE']) |
|
|
|
## ***************************************************************************** |
|
## DEFAULT DEFINITIONS |
|
## ***************************************************************************** |
|
# Can only be edited in the editor |
|
|
|
|
|
static func get_default_definitions() -> Dictionary: |
|
return load_json(get_config_files_paths()['DEFAULT_DEFINITIONS_FILE'], {'variables': [], 'glossary': []}) |
|
|
|
|
|
static func save_default_definitions(data: Dictionary): |
|
set_json(get_config_files_paths()['DEFAULT_DEFINITIONS_FILE'], data) |
|
|
|
|
|
static func get_default_definition_item(id: String): |
|
var data = get_default_definitions() |
|
return DialogicDefinitionsUtil.get_definition_by_id(data, id) |
|
|
|
|
|
static func set_default_definition_variable(id: String, name: String, value): |
|
# WARNING: For use in the editor only |
|
var data = get_default_definitions() |
|
DialogicDefinitionsUtil.set_definition_variable(data, id, name, value) |
|
save_default_definitions(data) |
|
|
|
|
|
static func set_default_definition_glossary(id: String, name: String, extra_title: String, extra_text: String, extra_extra: String): |
|
# WARNING: For use in the editor only |
|
var data = get_default_definitions() |
|
DialogicDefinitionsUtil.set_definition_glossary(data, id, name, extra_title, extra_text, extra_extra) |
|
save_default_definitions(data) |
|
|
|
|
|
static func delete_default_definition(id: String): |
|
# WARNING: For use in the editor only |
|
var data = get_default_definitions() |
|
DialogicDefinitionsUtil.delete_definition(data, id) |
|
save_default_definitions(data) |
|
|
|
|
|
|
|
## ***************************************************************************** |
|
## SAVES DURING GAME |
|
## ***************************************************************************** |
|
# Folders in the user://dialogic directory function as save_slots. |
|
|
|
# retruns a list of all save folders. |
|
# -> this returns a list of the save_slot-names |
|
static func get_saves_folders() -> Array: |
|
var save_folders = [] |
|
var directory := Directory.new() |
|
if directory.open(WORKING_DIR) != OK: |
|
print("[D] Error: Failed to access working directory.") |
|
return [] |
|
|
|
directory.list_dir_begin() |
|
var file_name = directory.get_next() |
|
while file_name != "": |
|
if directory.current_is_dir() and not file_name.begins_with("."): |
|
save_folders.append(file_name) |
|
file_name = directory.get_next() |
|
|
|
return save_folders |
|
|
|
# this adds a new save folder with the given name |
|
static func add_save_folder(save_name: String) -> void: |
|
var directory := Directory.new() |
|
if directory.open(WORKING_DIR) != OK: |
|
print("[D] Error: Failed to access working directory.") |
|
return |
|
directory.make_dir(save_name) |
|
|
|
var file := File.new() |
|
if file.open(WORKING_DIR+"/"+save_name+"/definitions.json", File.WRITE) == OK: |
|
file.store_string('') |
|
file.close() |
|
if file.open(WORKING_DIR+"/"+save_name+"/state.json", File.WRITE) == OK: |
|
file.store_string('') |
|
file.close() |
|
|
|
# this removes the given folder |
|
static func remove_save_folder(save_name: String) -> void: |
|
var directory := Directory.new() |
|
if directory.open(WORKING_DIR+"/"+save_name) != OK: |
|
print("[D] Error: Failed to access save folder '"+save_name+"'.") |
|
return |
|
|
|
directory.list_dir_begin() |
|
var file_name = directory.get_next() |
|
while file_name != "": |
|
directory.remove(file_name) |
|
file_name = directory.get_next() |
|
directory.remove(WORKING_DIR+"/"+save_name) |
|
|
|
# reset the definitions and state of the given save folder (or default) |
|
static func reset_save(save_name: String = '') -> void: |
|
save_state_info(save_name, {}) |
|
save_definitions(save_name, get_default_definitions()) |
|
|
|
# saves the state_info into the state.json file in the save folder "save_name" |
|
static func save_state_info(save_name: String, state_info: Dictionary) -> void: |
|
if save_name == '': |
|
set_json(get_config_files_paths()['STATE_DEFAULT_SAVE'], state_info) |
|
return |
|
|
|
if not save_name in get_saves_folders(): |
|
add_save_folder(save_name) |
|
|
|
set_json(WORKING_DIR+"/"+save_name+"/state.json", state_info) |
|
|
|
# return the state_info from the state.json file in the save folder "save_name" |
|
static func get_saved_state_info(save_name: String) -> Dictionary: |
|
if save_name == '': |
|
return load_json(get_config_files_paths()['STATE_DEFAULT_SAVE'], {}) |
|
|
|
if not save_name in get_saves_folders(): |
|
return {} |
|
|
|
return load_json(WORKING_DIR+"/"+save_name+"/state.json", {}) |
|
|
|
# saves the given definitions into the definitions.json file in the save folder "save name" |
|
static func save_definitions(save_name: String, definitions_info: Dictionary) -> void: |
|
if save_name == "": |
|
set_json(get_config_files_paths()['DEFINITIONS_DEFAULT_SAVE'], definitions_info) |
|
return |
|
|
|
if not save_name in get_saves_folders(): |
|
add_save_folder(save_name) |
|
|
|
set_json(WORKING_DIR+"/"+save_name+"/definitions.json", definitions_info) |
|
|
|
# return the definition info from the definiiotn.json in the save folder "save name" |
|
static func get_saved_definitions(save_name: String = '') -> Dictionary: |
|
if save_name == '': |
|
return load_json(get_config_files_paths()['DEFINITIONS_DEFAULT_SAVE'], get_default_definitions()) |
|
|
|
if not save_name in get_saves_folders(): |
|
print("[D] Wasn't able to find save '"+save_name+"'. Loaded the default definitions.") |
|
return get_default_definitions() |
|
|
|
return load_json(WORKING_DIR+"/"+save_name+"/definitions.json", {}) |
|
|
|
|
|
|
|
## ***************************************************************************** |
|
## FOLDER STRUCTURE |
|
## ***************************************************************************** |
|
# The DialogicEditor uses a fake folder structure |
|
# Can only be edited in the editor |
|
|
|
static func get_resource_folder_structure() -> Dictionary: |
|
return load_json(get_config_files_paths()['FOLDER_STRUCTURE_FILE'], |
|
{"folders": |
|
{"Timelines": |
|
{ |
|
"folders":{}, |
|
"files":[], |
|
'metadata':{'color':null, 'folded':false} |
|
}, |
|
"Characters": |
|
{ |
|
"folders":{}, |
|
"files":[], |
|
'metadata':{'color':null, 'folded':false} |
|
}, |
|
"Definitions": |
|
{ |
|
"folders":{}, |
|
"files":[], |
|
'metadata':{'color':null, 'folded':false} |
|
}, |
|
"Themes": |
|
{ |
|
"folders":{}, |
|
"files":[], |
|
'metadata':{'color':null, 'folded':false} |
|
}, |
|
}, |
|
"files":[] |
|
}) |
|
|
|
static func save_resource_folder_structure(data): |
|
set_json(get_config_files_paths()['FOLDER_STRUCTURE_FILE'], data)
|
|
|