No Description
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.

DialogicResources.gd 9.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354
  1. tool
  2. class_name DialogicResources
  3. const RESOURCES_DIR: String = "res://dialogic" # Readonly, used for static data
  4. const WORKING_DIR: String = "user://dialogic" # Readwrite, used for saves
  5. static func load_json(path: String, default: Dictionary={}) -> Dictionary:
  6. # An easy function to load json files and handle common errors.
  7. var file := File.new()
  8. if file.open(path, File.READ) != OK:
  9. file.close()
  10. return default
  11. var data_text: String = file.get_as_text()
  12. file.close()
  13. if data_text.empty():
  14. return default
  15. var data_parse: JSONParseResult = JSON.parse(data_text)
  16. if data_parse.error != OK:
  17. return default
  18. var final_data = data_parse.result
  19. if typeof(final_data) == TYPE_DICTIONARY:
  20. return final_data
  21. # If everything else fails
  22. return default
  23. static func init_dialogic_files() -> void:
  24. # This functions makes sure that the needed files and folders
  25. # exists when the plugin is loaded. If they don't, we create
  26. # them.
  27. # WARNING: only call while in the editor
  28. var directory = Directory.new()
  29. var paths = get_working_directories()
  30. var files = get_config_files_paths()
  31. # Create directories
  32. for dir in paths:
  33. if not directory.dir_exists(paths[dir]):
  34. directory.make_dir_recursive(paths[dir])
  35. # Create empty files
  36. for f in files:
  37. if not directory.file_exists(files[f]):
  38. create_empty_file(files[f])
  39. static func get_working_directories() -> Dictionary:
  40. return {
  41. 'RESOURCES_DIR': RESOURCES_DIR,
  42. 'WORKING_DIR': WORKING_DIR,
  43. 'TIMELINE_DIR': RESOURCES_DIR + "/timelines",
  44. 'THEME_DIR': RESOURCES_DIR + "/themes",
  45. 'CHAR_DIR': RESOURCES_DIR + "/characters",
  46. }
  47. static func get_config_files_paths() -> Dictionary:
  48. return {
  49. 'SETTINGS_FILE': RESOURCES_DIR + "/settings.cfg",
  50. 'DEFAULT_DEFINITIONS_FILE': RESOURCES_DIR + "/definitions.json",
  51. 'SAVED_DEFINITIONS_FILE': WORKING_DIR + "/definitions.json",
  52. 'SAVED_STATE_FILE': WORKING_DIR + "/state.json",
  53. }
  54. static func init_saves(overwrite: bool=true):
  55. var err = init_working_dir()
  56. var paths := get_config_files_paths()
  57. if err == OK:
  58. init_state_saves(overwrite)
  59. init_definitions_saves(overwrite)
  60. else:
  61. print('[Dialogic] Error creating working directory: ' + str(err))
  62. static func init_working_dir():
  63. var directory := Directory.new()
  64. return directory.make_dir_recursive(get_working_directories()['WORKING_DIR'])
  65. static func init_state_saves(overwrite: bool=true):
  66. var file := File.new()
  67. var paths := get_config_files_paths()
  68. if not file.file_exists(paths["SAVED_STATE_FILE"]) or overwrite:
  69. var err = file.open(paths["SAVED_STATE_FILE"], File.WRITE)
  70. if err == OK:
  71. file.store_string('')
  72. file.close()
  73. else:
  74. print('[Dialogic] Error opening saved state file: ' + str(err))
  75. static func init_definitions_saves(overwrite: bool=true):
  76. var directory := Directory.new()
  77. var source := File.new()
  78. var sink := File.new()
  79. var paths := get_config_files_paths()
  80. var err
  81. if not directory.file_exists(paths["SAVED_DEFINITIONS_FILE"]):
  82. err = sink.open(paths["SAVED_DEFINITIONS_FILE"], File.WRITE)
  83. print('[Dialogic] Saved definitions not present, creating file: ' + str(err))
  84. if err == OK:
  85. sink.store_string('')
  86. sink.close()
  87. else:
  88. print('[Dialogic] Error opening saved definitions file: ' + str(err))
  89. err = sink.open(paths["SAVED_DEFINITIONS_FILE"], File.READ_WRITE)
  90. if err == OK:
  91. if overwrite or sink.get_len() == 0:
  92. err = source.open(paths["DEFAULT_DEFINITIONS_FILE"], File.READ)
  93. if err == OK:
  94. sink.store_string(source.get_as_text())
  95. else:
  96. print('[Dialogic] Error opening default definitions file: ' + str(err))
  97. else:
  98. print('[Dialogic] Did not overwrite previous saved definitions')
  99. else:
  100. print('[Dialogic] Error opening saved definitions file: ' + str(err))
  101. source.close()
  102. sink.close()
  103. static func get_path(name: String, extra: String ='') -> String:
  104. var paths: Dictionary = get_working_directories()
  105. if extra != '':
  106. return paths[name] + '/' + extra
  107. else:
  108. return paths[name]
  109. static func get_filename_from_path(path: String, extension = false) -> String:
  110. var file_name: String = path.split('/')[-1]
  111. if extension == false:
  112. file_name = file_name.split('.')[0]
  113. return file_name
  114. static func listdir(path: String) -> Array:
  115. # https://docs.godotengine.org/en/stable/classes/class_directory.html#description
  116. var files: Array = []
  117. var dir := Directory.new()
  118. var err = dir.open(path)
  119. if err == OK:
  120. dir.list_dir_begin()
  121. var file_name = dir.get_next()
  122. while file_name != "":
  123. if not dir.current_is_dir() and not file_name.begins_with("."):
  124. files.append(file_name)
  125. file_name = dir.get_next()
  126. dir.list_dir_end()
  127. else:
  128. print("[Dialogic] Error while accessing path " + path + " - Error: " + str(err))
  129. return files
  130. static func create_empty_file(path):
  131. var file = File.new()
  132. file.open(path, File.WRITE)
  133. file.store_string('')
  134. file.close()
  135. # CONFIG UTIL
  136. static func get_config(id: String) -> ConfigFile:
  137. var paths := get_config_files_paths()
  138. var config := ConfigFile.new()
  139. if id in paths.keys():
  140. var err = config.load(paths[id])
  141. if err != OK:
  142. print("[Dialogic] Error while opening config file " + paths[id] + ". Error: " + str(err))
  143. return config
  144. # FILE UTIL
  145. static func remove_file(path: String):
  146. var dir = Directory.new()
  147. dir.remove(path)
  148. # JSON UTIL
  149. static func set_json(path: String, data: Dictionary):
  150. var file = File.new()
  151. var err = file.open(path, File.WRITE)
  152. if err == OK:
  153. file.store_line(to_json(data))
  154. file.close()
  155. return err
  156. # TIMELINE
  157. # Can only be edited in the editor
  158. static func get_timeline_json(path: String):
  159. return load_json(get_path('TIMELINE_DIR', path))
  160. static func set_timeline(timeline: Dictionary):
  161. # WARNING: For use in the editor only
  162. set_json(get_path('TIMELINE_DIR', timeline['metadata']['file']), timeline)
  163. static func delete_timeline(filename: String):
  164. # WARNING: For use in the editor only
  165. remove_file(get_path('TIMELINE_DIR', filename))
  166. # CHARACTER
  167. # Can only be edited in the editor
  168. static func get_character_json(path: String):
  169. return load_json(get_path('CHAR_DIR', path))
  170. static func set_character(character: Dictionary):
  171. # WARNING: For use in the editor only
  172. set_json(get_path('CHAR_DIR', character['id']), character)
  173. static func delete_character(filename: String):
  174. # WARNING: For use in the editor only
  175. remove_file(get_path('CHAR_DIR', filename))
  176. # THEME
  177. # Can only be edited in the editor
  178. static func get_theme_config(filename: String):
  179. var config = ConfigFile.new()
  180. var path
  181. if filename.begins_with('res://'):
  182. path = filename
  183. else:
  184. path = get_path('THEME_DIR', filename)
  185. var err = config.load(path)
  186. if err == OK:
  187. return config
  188. static func set_theme_value(filename, section, key, value):
  189. # WARNING: For use in the editor only
  190. var config = get_theme_config(filename)
  191. config.set_value(section, key, value)
  192. config.save(get_path('THEME_DIR', filename))
  193. static func add_theme(filename: String):
  194. create_empty_file(get_path('THEME_DIR', filename))
  195. static func delete_theme(filename: String):
  196. remove_file(get_path('THEME_DIR', filename))
  197. # SETTINGS
  198. # Can only be edited in the editor
  199. static func get_settings_config() -> ConfigFile:
  200. return get_config("SETTINGS_FILE")
  201. static func set_settings_value(section: String, key: String, value):
  202. var config = get_settings_config()
  203. config.set_value(section, key, value)
  204. config.save(get_config_files_paths()['SETTINGS_FILE'])
  205. # STATE
  206. static func get_saved_state() -> Dictionary:
  207. return load_json(get_config_files_paths()['SAVED_STATE_FILE'], {'general': {}})
  208. static func save_saved_state_config(data: Dictionary):
  209. set_json(get_config_files_paths()['SAVED_STATE_FILE'], data)
  210. static func get_saved_state_general_key(key: String) -> String:
  211. var data = get_saved_state()
  212. if key in data['general'].keys():
  213. return data['general'][key]
  214. else:
  215. return ''
  216. static func set_saved_state_general_key(key: String, value):
  217. var data = get_saved_state()
  218. data['general'][key] = str(value)
  219. save_saved_state_config(data)
  220. # DEFAULT DEFINITIONS
  221. # Can only be edited in the editor
  222. static func get_default_definitions() -> Dictionary:
  223. return load_json(get_config_files_paths()['DEFAULT_DEFINITIONS_FILE'], {'variables': [], 'glossary': []})
  224. static func save_default_definitions(data: Dictionary):
  225. set_json(get_config_files_paths()['DEFAULT_DEFINITIONS_FILE'], data)
  226. static func get_default_definition_item(id: String):
  227. var data = get_default_definitions()
  228. return DialogicDefinitionsUtil.get_definition_by_id(data, id)
  229. static func set_default_definition_variable(id: String, name: String, value):
  230. # WARNING: For use in the editor only
  231. var data = get_default_definitions()
  232. DialogicDefinitionsUtil.set_definition_variable(data, id, name, value)
  233. save_default_definitions(data)
  234. static func set_default_definition_glossary(id: String, name: String, extra_title: String, extra_text: String, extra_extra: String):
  235. # WARNING: For use in the editor only
  236. var data = get_default_definitions()
  237. DialogicDefinitionsUtil.set_definition_glossary(data, id, name, extra_title, extra_text, extra_extra)
  238. save_default_definitions(data)
  239. static func delete_default_definition(id: String):
  240. # WARNING: For use in the editor only
  241. var data = get_default_definitions()
  242. DialogicDefinitionsUtil.delete_definition(data, id)
  243. save_default_definitions(data)
  244. # SAVED DEFINITIONS
  245. # Can be edited at runtime, and will persist across runs
  246. static func get_saved_definitions() -> Dictionary:
  247. return load_json(get_config_files_paths()['SAVED_DEFINITIONS_FILE'], {'variables': [], 'glossary': []})
  248. static func save_saved_definitions(data: Dictionary):
  249. return set_json(get_config_files_paths()['SAVED_DEFINITIONS_FILE'], data)