update dialogic

This commit is contained in:
Arnaud Vergnet 2021-03-25 22:46:46 +01:00
parent a1212b0f70
commit 2fc0420194
15 changed files with 516 additions and 261 deletions

View file

@ -3,7 +3,7 @@ extends ScrollContainer
var editor_reference
onready var master_tree = get_node('../MasterTree')
var current_section = ''
var current_definition = null
onready var nodes = {
'name' : $VBoxContainer/HBoxContainer/VBoxContainer/Name,
@ -22,19 +22,19 @@ func _ready():
nodes['type'].connect('item_selected', self, '_on_type_selected')
func load_definition(section):
current_section = section
func load_definition(id):
current_definition = DialogicResources.get_default_definition_item(id)
reset_editor()
nodes['name'].editable = true
nodes['name'].text = get_definition('name', 'Unnamed')
var type = get_definition('type', 0)
nodes['name'].text = current_definition['name']
var type = current_definition['type']
nodes['type'].select(type)
if type == 0:
nodes['value'].text = get_definition('value', '')
nodes['value'].text = current_definition['value']
if type == 1:
nodes['extra_title'].text = get_definition('extra_title', '')
nodes['extra_text'].text = get_definition('extra_text', '')
nodes['extra_extra'].text = get_definition('extra_extra', '')
nodes['extra_title'].text = current_definition['title']
nodes['extra_text'].text = current_definition['text']
nodes['extra_extra'].text = current_definition['extra']
show_sub_editor(type)
@ -44,7 +44,10 @@ func reset_editor():
nodes['extra_title'].text = ''
nodes['extra_text'].text = ''
nodes['extra_extra'].text = ''
nodes['type'].select(get_definition('type', 0))
var type = 0
if current_definition != null:
type = current_definition['type']
nodes['type'].select(type)
func _on_name_changed(text):
@ -70,23 +73,16 @@ func show_sub_editor(type):
nodes['extra_editor'].visible = true
func get_definition(key: String, default):
if current_section != '':
return DialogicResources.get_default_definition_key(current_section, key, default)
else:
return default
func new_definition():
var section = DialogicUtil.generate_random_id()
DialogicResources.add_default_definition_variable(section, 'New definition', 0, '')
master_tree.add_definition({'section': section,'name': 'New definition', 'type': 0}, true)
var id = DialogicUtil.generate_random_id()
DialogicResources.set_default_definition_variable(id, 'New definition', '')
master_tree.add_definition({'id': id, 'name': 'New definition', 'type': 0}, true)
func save_definition():
if current_section != '':
if current_definition['id'] != '':
var type: int = nodes['type'].selected
if type == 0:
DialogicResources.set_default_definition_variable(current_section, nodes['name'].text, nodes['value'].text)
DialogicResources.set_default_definition_variable(current_definition['id'], nodes['name'].text, nodes['value'].text)
if type == 1:
DialogicResources.set_default_definition_glossary(current_section, nodes['name'].text, nodes['extra_title'].text, nodes['extra_text'].text, nodes['extra_extra'].text)
DialogicResources.set_default_definition_glossary(current_definition['id'], nodes['name'].text, nodes['extra_title'].text, nodes['extra_text'].text, nodes['extra_extra'].text)

View file

@ -67,9 +67,9 @@ func _on_TimelinePopupMenu_id_pressed(id):
func _on_RemoveTimelineConfirmation_confirmed():
var dir = Directory.new()
var target = $MainPanel/TimelineEditor.working_timeline_file
var target = $MainPanel/TimelineEditor.timeline_file
print('target: ', target)
dir.remove(target)
DialogicResources.delete_timeline(target)
$MainPanel/MasterTree.remove_selected()
$MainPanel/MasterTree.hide_all_editors(true)
@ -99,7 +99,7 @@ func _on_DefinitionPopupMenu_id_pressed(id):
func _on_RemoveDefinitionConfirmation_confirmed():
var target = $MainPanel/DefinitionEditor.current_section
var target = $MainPanel/DefinitionEditor.current_definition['id']
DialogicResources.delete_default_definition(target)
$MainPanel/MasterTree.remove_selected()
$MainPanel/MasterTree.hide_all_editors(true)
@ -114,7 +114,7 @@ func _on_RemoveCharacterConfirmation_confirmed():
func _on_RemoveThemeConfirmation_confirmed():
var filename = $MainPanel/MasterTree.get_selected().get_metadata(0)['file']
DialogicResources.delete_timeline(filename)
DialogicResources.delete_theme(filename)
$MainPanel/MasterTree.remove_selected()
$MainPanel/MasterTree.hide_all_editors(true)

View file

@ -69,7 +69,7 @@ func _ready():
add_character(c)
# Adding Definitions
for d in DialogicUtil.get_default_definition_list():
for d in DialogicUtil.get_default_definitions_list():
add_definition(d)
# Adding Themes
@ -155,7 +155,7 @@ func _on_item_selected():
character_editor.load_character(metadata['file'])
if metadata['editor'] == 'Definition':
definition_editor.visible = true
definition_editor.load_definition(metadata['section'])
definition_editor.load_definition(metadata['id'])
if metadata['editor'] == 'Theme':
theme_editor.load_theme(metadata['file'])
theme_editor.visible = true

View file

@ -12,13 +12,12 @@ func _ready():
func _on_MenuButton_about_to_show():
get_popup().clear()
var index = 0
for d in DialogicUtil.get_default_definition_list():
if d['type'] == 0:
get_popup().add_item(d['name'])
get_popup().set_item_metadata(index, {
'section': d['section'],
})
index += 1
for d in DialogicResources.get_default_definitions()['variables']:
get_popup().add_item(d['name'])
get_popup().set_item_metadata(index, {
'id': d['id'],
})
index += 1
func _on_entry_selected(index):
@ -27,10 +26,10 @@ func _on_entry_selected(index):
text = _text
func load_definition(section):
if section != '':
for d in DialogicUtil.get_default_definition_list():
if d['section'] == section:
func load_definition(id):
if id != '':
for d in DialogicResources.get_default_definitions()['variables']:
if d['id'] == id:
text = d['name']
else:
text = default_text

View file

@ -36,7 +36,7 @@ func load_data(data):
func _on_definition_entry_selected(index):
var metadata = nodes['definition_picker'].get_popup().get_item_metadata(index)
event_data['definition'] = metadata['section']
event_data['definition'] = metadata['id']
func _on_condition_entry_selected(index):

View file

@ -21,7 +21,7 @@ func _ready():
func _on_definition_entry_selected(index):
var metadata = nodes['definition_picker'].get_popup().get_item_metadata(index)
event_data['definition'] = metadata['section']
event_data['definition'] = metadata['id']
func load_data(data):

View file

@ -323,4 +323,4 @@ func _on_Alignment_item_selected(index):
func _on_Preview_text_changed():
DialogicUtil.set_theme_value(current_theme, 'text', 'preview', n['text_preview'].text)
DialogicResources.set_theme_value(current_theme, 'text', 'preview', n['text_preview'].text)

View file

@ -10,15 +10,20 @@ var waiting_for_answer: bool = false
var waiting_for_input: bool = false
var waiting = false
var preview = false
var definitions
var definitions = {}
var definition_visible = false
var settings
var current_theme
var current_timeline := ''
## The timeline to load when starting the scene
export(String, "TimelineDropdown") var timeline: String
## Should we clear saved data (definitions and timeline progress) on start?
export(bool) var reset_saves = true
## Should we show debug information when running?
export(bool) var debug_mode = true
signal event_start(type, event)
signal event_end(type)
signal dialogic_signal(value)
@ -35,13 +40,15 @@ func _ready():
# Loading the config files
load_config_files()
# Make sure saves are ready
DialogicResources.init_definitions_saves(reset_saves)
# Checking if the dialog should read the code from a external file
if timeline != '':
dialog_script = set_current_dialog(timeline + '.json')
if not timeline.empty():
dialog_script = set_current_dialog(timeline)
elif dialog_script.keys().size() == 0:
dialog_script = {
"events":[{"character":"","portrait":"",
"text":"[Dialogic Error] No timeline specified."}]
}
# Connecting resize signal
get_viewport().connect("size_changed", self, "resize_main")
resize_main()
@ -55,12 +62,17 @@ func _ready():
# Getting the character information
characters = DialogicUtil.get_character_list()
if Engine.is_editor_hint() == false:
if not Engine.is_editor_hint():
load_dialog()
func load_config_files():
definitions = DialogicUtil.get_definition_list()
if not Engine.is_editor_hint():
# Make sure saves are ready
DialogicSingleton.init(reset_saves)
definitions = DialogicSingleton.get_definitions()
else:
definitions = DialogicResources.get_default_definitions()
settings = DialogicResources.get_settings_config()
var theme_file = 'res://addons/dialogic/Editor/ThemeEditor/default-theme.cfg'
if settings.has_section('theme'):
@ -80,7 +92,8 @@ func resize_main():
$TextBubble.rect_position.y = (rect_size.y) - ($TextBubble.rect_size.y) - current_theme.get_value('box', 'bottom_gap', 40)
func set_current_dialog(dialog_path):
func set_current_dialog(dialog_path: String):
current_timeline = dialog_path
var dialog_script = DialogicResources.get_timeline_json(dialog_path)
# All this parse events should be happening in the same loop ideally
# But until performance is not an issue I will probably stay lazy
@ -217,7 +230,6 @@ func parse_branches(dialog_script: Dictionary) -> Dictionary:
func parse_definitions(text: String):
var words = []
var definition_list = DialogicUtil.get_definition_list()
if Engine.is_editor_hint():
# Loading variables again to avoid issues in the preview dialog
load_config_files()
@ -229,11 +241,9 @@ func parse_definitions(text: String):
func _insert_variable_definitions(text: String):
var final_text := text;
for d in definitions:
if d['type'] == 0:
var name : String = d['name'];
var value = DialogicUtil.get_var(name)
final_text = final_text.replace('[' + name + ']', value)
for d in definitions['variables']:
var name : String = d['name'];
final_text = final_text.replace('[' + name + ']', d['value'])
return final_text;
@ -241,13 +251,12 @@ func _insert_glossary_definitions(text: String):
var color = self.current_theme.get_value('definitions', 'color', '#ffbebebe')
var final_text := text;
# I should use regex here, but this is way easier :)
for d in definitions:
if d['type'] == 1:
final_text = final_text.replace(d['name'],
'[url=' + d['section'] + ']' +
'[color=' + color + ']' + d['name'] + '[/color]' +
'[/url]'
)
for d in definitions['glossary']:
final_text = final_text.replace(d['name'],
'[url=' + d['id'] + ']' +
'[color=' + color + ']' + d['name'] + '[/color]' +
'[/url]'
)
return final_text;
@ -309,13 +318,26 @@ func update_text(text):
return true
func on_timeline_start():
if not Engine.is_editor_hint():
DialogicSingleton.save_definitions()
DialogicSingleton.set_current_timeline(current_timeline)
emit_signal("event_start", "timeline", current_timeline)
func on_timeline_end():
if not Engine.is_editor_hint():
DialogicSingleton.save_definitions()
DialogicSingleton.set_current_timeline('')
emit_signal("event_end", "timeline")
func load_dialog(skip_add = false):
# Emitting signals
if dialog_script.has('events'):
if dialog_index == 0:
emit_signal("event_start", "timeline", timeline)
on_timeline_start()
elif dialog_index == dialog_script['events'].size():
emit_signal("event_end", "timeline")
on_timeline_end()
# Hiding definitions popup
definition_visible = false
@ -346,8 +368,6 @@ func get_character(character_id):
func event_handler(event: Dictionary):
# Handling an event and updating the available nodes accordingly.
reset_dialog_extras()
# Updating the settings and definitions in case that they were modified by a timelien
load_config_files()
dprint('[D] Current Event: ', event)
match event:
@ -440,6 +460,7 @@ func event_handler(event: Dictionary):
go_to_next_event()
{'close_dialog'}:
emit_signal("event_start", "close_dialog", event)
on_timeline_end()
queue_free()
{'set_theme'}:
emit_signal("event_start", "set_theme", event)
@ -458,11 +479,12 @@ func event_handler(event: Dictionary):
# Treating this conditional as an option on a regular question event
var def_value = null
var current_question = questions[event['question_id']]
for d in definitions:
if d['section'] == event['definition']:
def_value = DialogicUtil.get_var(d['name'])
var condition_met = self._compare_definitions(def_value, event['value'], event['condition']);
for d in definitions['variables']:
if d['id'] == event['definition']:
def_value = d['value']
var condition_met = def_value != null and _compare_definitions(def_value, event['value'], event['condition']);
current_question['answered'] = !condition_met
if !condition_met:
@ -474,7 +496,7 @@ func event_handler(event: Dictionary):
go_to_next_event()
{'set_value', 'definition'}:
emit_signal("event_start", "set_value", event)
DialogicResources.set_saved_definition_variable_value(event['definition'], event['set_value'])
DialogicSingleton.set_variable_from_id(event['definition'], event['set_value'])
go_to_next_event()
_:
visible = false
@ -570,7 +592,6 @@ func _on_option_selected(option, variable, value):
waiting_for_answer = false
reset_options()
load_dialog()
#print(dialog_resource.custom_variables)
dprint('[!] Option selected: ', option.text, ' value= ' , value)
@ -684,17 +705,16 @@ func load_theme(filename):
func _on_RichTextLabel_meta_hover_started(meta):
var correct_type = false
for d in definitions:
if d['section'] == meta:
if d['type'] == 1:
$DefinitionInfo.load_preview({
'title': d['config'].get_value(d['section'], 'extra_title', ''),
'body': d['config'].get_value(d['section'], 'extra_text', ''),
'extra': d['config'].get_value(d['section'], 'extra_extra', ''),
'color': current_theme.get_value('definitions', 'color', '#ffbebebe'),
})
correct_type = true
print(d)
for d in definitions['glossary']:
if d['id'] == meta:
$DefinitionInfo.load_preview({
'title': d['title'],
'body': d['text'],
'extra': d['extra'],
'color': current_theme.get_value('definitions', 'color', '#ffbebebe'),
})
correct_type = true
print(d)
if correct_type:
definition_visible = true

View file

@ -1,29 +1,137 @@
extends Node
## Exposed and safe to use methods for Dialogic
## See documentation here:
## https://github.com/coppolaemilio/dialogic
## ### /!\ ###
## Do not use methods from other classes as it could break the plugin's integrity
## ### /!\ ###
##
## Trying to follow this documentation convention: https://github.com/godotengine/godot/pull/41095
class_name Dialogic
static func start(timeline: String, dialog_scene_path: String="res://addons/dialogic/Dialog.tscn", debug_mode: bool=false):
var dialog = load(dialog_scene_path)
## Starts the dialog for the given timeline and returns a Dialog node.
## You must then add it manually to the scene to display the dialog.
##
## Example:
## var new_dialog = Dialogic.start('Your Timeline Name Here')
## add_child(new_dialog)
##
## This is exactly the same as using the editor:
## you can drag and drop the scene located at /addons/dialogic/Dialog.tscn
## and set the current timeline via the inspector.
##
## @param timeline The timeline to load. You can provide the timeline name or the filename.
## @param reset_saves True to reset dialogic saved data such as definitions.
## @param dialog_scene_path If you made a custom Dialog scene or moved it from its default path, you can specify its new path here.
## @param debug_mode Debug is disabled by default but can be enabled if needed.
## @returns A Dialog node to be added into the scene tree.
static func start(timeline: String, reset_saves: bool=true, dialog_scene_path: String="res://addons/dialogic/Dialog.tscn", debug_mode: bool=false):
var dialog: = load(dialog_scene_path)
var d = dialog.instance()
d.reset_saves = reset_saves
d.debug_mode = debug_mode
for t in DialogicUtil.get_timeline_list():
if t['name'] == timeline:
d.timeline = t['file'].replace('.json', '')
return d
d.dialog_script = {
"events":[{"character":"","portrait":"",
"text":"[Dialogic Error] Loading dialog [color=red]" + timeline + "[/color]. It seems like the timeline doesn't exists. Maybe the name is wrong?"}]
}
if not timeline.empty():
for t in DialogicUtil.get_timeline_list():
if t['name'] == timeline or t['file'] == timeline:
d.timeline = t['file']
return d
d.dialog_script = {
"events":[{"character":"","portrait":"",
"text":"[Dialogic Error] Loading dialog [color=red]" + timeline + "[/color]. It seems like the timeline doesn't exists. Maybe the name is wrong?"}]
}
return d
static func reset_saves():
DialogicResources.init_definitions_saves(true)
## Same as the start method above, but using the last timeline saved.
##
## @param initial_timeline The timeline to load in case no save is found.
## @param dialog_scene_path If you made a custom Dialog scene or moved it from its default path, you can specify its new path here.
## @param debug_mode Debug is disabled by default but can be enabled if needed.
## @returns A Dialog node to be added into the scene tree.
static func start_from_save(initial_timeline: String, dialog_scene_path: String="res://addons/dialogic/Dialog.tscn", debug_mode: bool=false):
var current := get_current_timeline()
if current.empty():
current = initial_timeline
return start(current, false, dialog_scene_path, debug_mode)
## Gets default values for definitions.
##
## @returns Dictionary in the format {'variables': [], 'glossary': []}
static func get_default_definitions() -> Dictionary:
return DialogicSingleton.get_default_definitions()
static func get_var(variable: String):
return DialogicUtil.get_var(variable)
## Gets currently saved values for definitions.
##
## @returns Dictionary in the format {'variables': [], 'glossary': []}
static func get_definitions() -> Dictionary:
return DialogicSingleton.get_definitions()
static func set_var(variable: String, value):
DialogicUtil.set_var(variable, value)
## Save current definitions to the filesystem.
## Definitions are automatically saved on timeline start/end
##
## @returns Error status, OK if all went well
func save_definitions():
return DialogicSingleton.save_definitions()
## Resets data to default values. This is the same as calling start with reset_saves to true
func reset_saves():
DialogicSingleton.init(true)
## Gets the value for the variable with the given name.
## The returned value is a String but can be easily converted into a number
## using Godot built-in methods:
## [`is_valid_float`](https://docs.godotengine.org/en/stable/classes/class_string.html#class-string-method-is-valid-float)
## [`float()`](https://docs.godotengine.org/en/stable/classes/class_float.html#class-float-method-float).
##
## @param name The name of the variable to find.
## @returns The variable's value as string, or an empty string if not found.
static func get_variable(name: String) -> String:
return DialogicSingleton.get_variable(name)
## Sets the value for the variable with the given name.
## The given value will be converted to string using the
## [`str()`](https://docs.godotengine.org/en/stable/classes/class_string.html) function.
##
## @param name The name of the variable to edit.
## @param value The value of the variable to set.
static func set_variable(name: String, value) -> void:
DialogicSingleton.set_variable(name, value)
## Gets the glossary data for the definition with the given name.
## Returned format:
## { title': '', 'text' : '', 'extra': '' }
##
## @param name The name of the glossary to find.
## @returns The glossary data as a Dictionary.
## A structure with empty strings is returned if the glossary was not found.
static func get_glossary(name: String) -> Dictionary:
return DialogicSingleton.get_glossary(name)
## Sets the data for the glossary of the given name.
##
## @param name The name of the glossary to edit.
## @param title The title to show in the information box.
## @param text The text to show in the information box.
## @param extra The extra information at the bottom of the box.
static func set_glossary(name: String, title: String, text: String, extra: String) -> void:
DialogicSingleton.set_glossary(name, title, text, extra)
## Gets the currently saved timeline.
## Timeline saves are set on timeline start, and cleared on end.
## This means you can keep track of timeline changes and detect when the dialog ends.
##
## @returns The current timeline filename, or an empty string if none was saved.
static func get_current_timeline() -> String:
return DialogicSingleton.get_current_timeline()

View file

@ -0,0 +1,71 @@
extends Node
class_name DialogicDefinitionsUtil
static func get_definition_by_key(data: Dictionary, key: String, value: String):
var variables : Array = data['variables']
var glossary : Array = data['glossary']
for v in variables:
if v[key] == value:
return v
for g in glossary:
if g[key] == value:
return g
return null
static func get_definition_by_id(data: Dictionary, id: String):
return get_definition_by_key(data, 'id', id)
static func get_definition_by_name(data: Dictionary, id: String):
return get_definition_by_key(data, 'name', id)
static func set_definition(section: String, data: Dictionary, elem: Dictionary):
delete_definition(data, elem['id'])
var array: Array = data[section]
var found = false;
for e in array:
if e['id'] == elem['id']:
found = true
array.erase(e)
array.append(elem)
break
if not found:
array.append(elem)
static func set_definition_variable(data: Dictionary, id: String, name: String, value):
set_definition('variables', data, {
'id': id,
'name': name,
'value': value,
'type': 0
})
static func set_definition_glossary(data: Dictionary, id: String, name: String, title: String, text: String, extra: String):
set_definition('glossary', data, {
'id': id,
'name': name,
'title': title,
'text': text,
'extra': extra,
'type': 1
})
static func delete_definition(data: Dictionary, id: String):
var variables : Array = data['variables']
var glossary : Array = data['glossary']
var item = get_definition_by_id(data, id);
if item != null:
if (item['type'] == 0):
variables.erase(item)
else:
glossary.erase(item)
static func definitions_json_to_array(data: Dictionary) -> Array:
return data['variables'] + data['glossary']

View file

@ -6,24 +6,26 @@ const RESOURCES_DIR: String = "res://dialogic" # Readonly, used for static data
const WORKING_DIR: String = "user://dialogic" # Readwrite, used for saves
static func load_json(path: String) -> Dictionary:
static func load_json(path: String, default: Dictionary={}) -> Dictionary:
# An easy function to load json files and handle common errors.
var file:File = File.new()
var file := File.new()
if file.open(path, File.READ) != OK:
file.close()
return {'error':'file read error'}
return default
var data_text: String = file.get_as_text()
file.close()
var data_parse:JSONParseResult = JSON.parse(data_text)
if data_text.empty():
return default
var data_parse: JSONParseResult = JSON.parse(data_text)
if data_parse.error != OK:
return {'error':'data parse error'}
return default
var final_data = data_parse.result
if typeof(final_data) == TYPE_DICTIONARY:
return final_data
# If everything else fails
return {'error':'data parse error'}
return default
static func init_dialogic_files() -> void:
@ -57,43 +59,68 @@ static func get_working_directories() -> Dictionary:
static func get_config_files_paths() -> Dictionary:
return {
'SETTINGS_FILE': RESOURCES_DIR + "/settings.cfg",
'DEFAULT_DEFINITIONS_FILE': RESOURCES_DIR + "/definitions.cfg",
'SAVED_DEFINITIONS_FILE': WORKING_DIR + "/definitions.cfg",
'DEFAULT_DEFINITIONS_FILE': RESOURCES_DIR + "/definitions.json",
'SAVED_DEFINITIONS_FILE': WORKING_DIR + "/definitions.json",
'SAVED_STATE_FILE': WORKING_DIR + "/state.json",
}
static func init_saves(overwrite: bool=true):
var err = init_working_dir()
var paths := get_config_files_paths()
if err == OK:
init_state_saves(overwrite)
init_definitions_saves(overwrite)
else:
print('Error creating working directory: ' + str(err))
static func init_working_dir():
var directory := Directory.new()
return directory.make_dir_recursive(get_working_directories()['WORKING_DIR'])
static func init_state_saves(overwrite: bool=true):
var file := File.new()
var paths := get_config_files_paths()
if not file.file_exists(paths["SAVED_STATE_FILE"]) or overwrite:
var err = file.open(paths["SAVED_STATE_FILE"], File.WRITE)
if err == OK:
file.store_string('')
file.close()
else:
print('Error opening saved state file: ' + str(err))
static func init_definitions_saves(overwrite: bool=true):
var directory := Directory.new()
var source := File.new()
var sink := File.new()
var paths := get_config_files_paths()
var err := directory.make_dir_recursive(get_working_directories()['WORKING_DIR'])
if err == OK:
if not directory.file_exists(paths["SAVED_DEFINITIONS_FILE"]):
err = sink.open(paths["SAVED_DEFINITIONS_FILE"], File.WRITE)
print('Saved definitions not present, creating file: ' + str(err))
if err == OK:
sink.store_string('')
sink.close()
else:
print('Error opening saved definitions file: ' + str(err))
err = sink.open(paths["SAVED_DEFINITIONS_FILE"], File.READ_WRITE)
var err
if not directory.file_exists(paths["SAVED_DEFINITIONS_FILE"]):
err = sink.open(paths["SAVED_DEFINITIONS_FILE"], File.WRITE)
print('Saved definitions not present, creating file: ' + str(err))
if err == OK:
if overwrite or sink.get_len() == 0:
err = source.open(paths["DEFAULT_DEFINITIONS_FILE"], File.READ)
if err == OK:
sink.store_string(source.get_as_text())
else:
print('Error opening default definitions file: ' + str(err))
else:
print('Did not overwrite previous saved definitions')
sink.store_string('')
sink.close()
else:
print('Error opening saved definitions file: ' + str(err))
err = sink.open(paths["SAVED_DEFINITIONS_FILE"], File.READ_WRITE)
if err == OK:
if overwrite or sink.get_len() == 0:
err = source.open(paths["DEFAULT_DEFINITIONS_FILE"], File.READ)
if err == OK:
sink.store_string(source.get_as_text())
else:
print('Error opening default definitions file: ' + str(err))
else:
print('Did not overwrite previous saved definitions')
else:
print('Error creating working directory: ' + str(err))
print('Error opening saved definitions file: ' + str(err))
source.close()
sink.close()
@ -163,30 +190,26 @@ static func remove_file(path: String):
# JSON UTIL
static func get_json(dir_id: String, path: String):
return load_json(get_path(dir_id, path))
static func set_json(dir_id: String, path: String, data: Dictionary):
var directory = Directory.new()
var base_path := get_path(dir_id)
if not directory.dir_exists(base_path):
directory.make_dir_recursive(base_path)
static func set_json(path: String, data: Dictionary):
var file = File.new()
file.open(get_path(dir_id, path), File.WRITE)
file.store_line(to_json(data))
file.close()
var err = file.open(path, File.WRITE)
if err == OK:
file.store_line(to_json(data))
file.close()
return err
# TIMELINE
# Can only be edited in the editor
static func get_timeline_json(path: String):
return get_json('TIMELINE_DIR', path)
return load_json(get_path('TIMELINE_DIR', path))
static func set_timeline(timeline: Dictionary):
# WARNING: For use in the editor only
set_json('TIMELINE_DIR', timeline['metadata']['file'], timeline)
set_json(get_path('TIMELINE_DIR', timeline['metadata']['file']), timeline)
static func delete_timeline(filename: String):
@ -195,15 +218,16 @@ static func delete_timeline(filename: String):
# CHARACTER
# Can only be edited in the editor
static func get_character_json(path: String):
return get_json('CHAR_DIR', path)
return load_json(get_path('CHAR_DIR', path))
static func set_character(character: Dictionary):
# WARNING: For use in the editor only
set_json('CHAR_DIR', character['id'], character)
set_json(get_path('CHAR_DIR', character['id']), character)
static func delete_character(filename: String):
@ -212,6 +236,7 @@ static func delete_character(filename: String):
# THEME
# Can only be edited in the editor
static func get_theme_config(filename: String):
@ -228,8 +253,6 @@ static func get_theme_config(filename: String):
static func set_theme_value(filename, section, key, value):
# WARNING: For use in the editor only
print('=> theme update')
print(filename)
var config = get_theme_config(filename)
config.set_value(section, key, value)
config.save(get_path('THEME_DIR', filename))
@ -239,10 +262,14 @@ 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))
# SETTINGS
# Can only be edited in the editor
static func get_settings_config():
static func get_settings_config() -> ConfigFile:
return get_config("SETTINGS_FILE")
@ -252,98 +279,76 @@ static func set_settings_value(section: String, key: String, value):
config.save(get_config_files_paths()['SETTINGS_FILE'])
# DEFINITIONS UTIL
# used by default and saved definitions
# STATE
static func get_definition_key(config_id: String, section: String, key: String, default):
var config = get_config(config_id)
if config.has_section(section):
return config.get_value(section, key, default)
static func get_saved_state() -> Dictionary:
return load_json(get_config_files_paths()['SAVED_STATE_FILE'], {'general': {}})
static func save_saved_state_config(data: Dictionary):
set_json(get_config_files_paths()['SAVED_STATE_FILE'], data)
static func get_saved_state_general_key(key: String) -> String:
var data = get_saved_state()
if key in data['general'].keys():
return data['general'][key]
else:
return default
return ''
static func set_definition_variable(config_id: String, section: String, name: String, value):
var config = get_config(config_id)
config.set_value(section, 'name', name)
config.set_value(section, 'type', 0)
config.set_value(section, 'value', str(value))
return config.save(get_config_files_paths()[config_id])
static func set_definition_glossary(config_id: String, section: String, name: String, extra_title: String, extra_text: String, extra_extra: String):
var config = get_config(config_id)
config.set_value(section, 'name', name)
config.set_value(section, 'type', 1)
config.set_value(section, 'extra_title', extra_title)
config.set_value(section, 'extra_text', extra_text)
config.set_value(section, 'extra_extra', extra_extra)
return config.save(get_config_files_paths()[config_id])
static func add_definition_variable(config_id: String, section: String, name: String, type: int, value):
var config = get_config(config_id)
config.set_value(section, 'name', name)
config.set_value(section, 'type', type)
config.set_value(section, 'value', str(value))
return config.save(get_config_files_paths()[config_id])
static func delete_definition(config_id: String, section: String):
var config = get_config(config_id)
config.erase_section(section)
return config.save(get_config_files_paths()[config_id])
static func set_saved_state_general_key(key: String, value):
var data = get_saved_state()
data['general'][key] = str(value)
save_saved_state_config(data)
# DEFAULT DEFINITIONS
# Can only be edited in the editor
static func get_default_definitions_config():
return get_config('DEFAULT_DEFINITIONS_FILE')
static func get_default_definitions() -> Dictionary:
return load_json(get_config_files_paths()['DEFAULT_DEFINITIONS_FILE'], {'variables': [], 'glossary': []})
static func get_default_definition_key(section: String, key: String, default):
return get_definition_key('DEFAULT_DEFINITIONS_FILE', section, key, default)
static func save_default_definitions(data: Dictionary):
set_json(get_config_files_paths()['DEFAULT_DEFINITIONS_FILE'], data)
static func set_default_definition_variable(section: String, name: String, value):
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
return set_definition_variable('DEFAULT_DEFINITIONS_FILE', section, name, value)
var data = get_default_definitions()
DialogicDefinitionsUtil.set_definition_variable(data, id, name, value)
save_default_definitions(data)
static func set_default_definition_glossary(section: String, name: String, extra_title: String, extra_text: String, extra_extra: String):
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
return set_definition_glossary('DEFAULT_DEFINITIONS_FILE', section, name, extra_title, extra_text, extra_extra)
var data = get_default_definitions()
DialogicDefinitionsUtil.set_definition_glossary(data, id, name, extra_title, extra_text, extra_extra)
save_default_definitions(data)
static func add_default_definition_variable(section: String, name: String, type: int, value):
static func delete_default_definition(id: String):
# WARNING: For use in the editor only
return add_definition_variable('DEFAULT_DEFINITIONS_FILE', section, name, type, value)
static func delete_default_definition(section: String):
# WARNING: For use in the editor only
return delete_definition('DEFAULT_DEFINITIONS_FILE', section)
var data = get_default_definitions()
DialogicDefinitionsUtil.delete_definition(data, id)
save_default_definitions(data)
# SAVED DEFINITIONS
# Can be edited at runtime, and will persist across runs
static func get_saved_definitions_config():
return get_config("SAVED_DEFINITIONS_FILE")
static func get_saved_definitions() -> Dictionary:
return load_json(get_config_files_paths()['SAVED_DEFINITIONS_FILE'], {'variables': [], 'glossary': []})
static func set_saved_definition_variable(section: String, name: String, value):
return set_definition_variable('SAVED_DEFINITIONS_FILE', section, name, value)
static func set_saved_definition_variable_value(section: String, value):
var config = get_saved_definitions_config()
return set_definition_variable('SAVED_DEFINITIONS_FILE', section, config.get_value(section, 'name', section), value)
static func set_saved_definition_glossary(section: String, name: String, extra_title: String, extra_text: String, extra_extra: String):
return set_definition_glossary('SAVED_DEFINITIONS_FILE', section, name, extra_title, extra_text, extra_extra)
static func save_saved_definitions(data: Dictionary):
return set_json(get_config_files_paths()['SAVED_DEFINITIONS_FILE'], data)

View file

@ -0,0 +1,86 @@
extends Node
var current_definitions := {}
var default_definitions := {}
var current_timeline := ''
func _init() -> void:
init(false)
func init(reset: bool=false) -> void:
# Loads saved definitions into memory
DialogicResources.init_saves(reset)
current_definitions = DialogicResources.get_saved_definitions()
default_definitions = DialogicResources.get_default_definitions()
current_timeline = DialogicResources.get_saved_state_general_key('timeline')
func get_definitions_list() -> Array:
return DialogicDefinitionsUtil.definitions_json_to_array(current_definitions)
func get_definitions() -> Dictionary:
return current_definitions
func get_default_definitions() -> Dictionary:
return default_definitions
func get_default_definitions_list() -> Array:
return DialogicDefinitionsUtil.definitions_json_to_array(default_definitions)
func save_definitions():
return DialogicResources.save_saved_definitions(current_definitions)
func get_variable(name: String) -> String:
for d in current_definitions['variables']:
if d['name'] == name:
return d['value']
return ''
func set_variable(name: String, value) -> void:
for d in current_definitions['variables']:
if d['name'] == name:
d['value'] = str(value)
func set_variable_from_id(id: String, value) -> void:
for d in current_definitions['variables']:
if d['id'] == id:
d['value'] = str(value)
func get_glossary(name: String) -> Dictionary:
for d in current_definitions['glossary']:
if d['name'] == name:
return d
return {
'title': '',
'text': '',
'extra': ''
}
func set_glossary(name: String, title: String, text: String, extra: String) -> void:
for d in current_definitions['glossary']:
if d['name'] == name:
d['title'] = title
d['text'] = text
d['extra'] = extra
func set_current_timeline(timeline: String):
current_timeline = timeline
DialogicResources.set_saved_state_general_key('timeline', timeline)
func get_current_timeline() -> String:
return current_timeline

View file

@ -68,43 +68,8 @@ static func get_theme_list() -> Array:
return themes
static func get_default_definition_list() -> Array:
var definitions: Array = []
var config = DialogicResources.get_default_definitions_config()
for section in config.get_sections():
definitions.append({
'section': section,
'name': config.get_value(section, 'name', section),
'config': config,
'type': config.get_value(section, 'type', 0),
})
return definitions
static func get_definition_list() -> Array:
var definitions: Array = []
var config = DialogicResources.get_saved_definitions_config()
for section in config.get_sections():
definitions.append({
'section': section,
'name': config.get_value(section, 'name', section),
'config': config,
'type': config.get_value(section, 'type', 0),
})
return definitions
static func get_var(variable: String) -> String:
for d in get_definition_list():
if d['name'] == variable:
return d['config'].get_value(d['section'], 'value')
return ''
static func set_var(variable: String, value) -> void:
for d in get_definition_list():
if d['name'] == variable:
DialogicResources.set_saved_definition_variable(d['section'], d['name'], value)
static func get_default_definitions_list() -> Array:
return DialogicDefinitionsUtil.definitions_json_to_array(DialogicResources.get_default_definitions())
static func generate_random_id() -> String:

View file

@ -36,7 +36,7 @@ func _about_to_show_menu():
func _on_timeline_selected(index):
var text = timelines_dropdown.get_popup().get_item_text(index)
var metadata = timelines_dropdown.get_popup().get_item_metadata(index)
current_value = metadata['file'].replace('.json', '')
current_value = metadata['file']
timelines_dropdown.text = text
emit_changed(get_edited_property(), current_value)
@ -52,6 +52,6 @@ func update_property():
current_value = new_value
# Checking for the display name
for c in DialogicUtil.get_timeline_list():
if c['file'].replace('.json', '') == current_value:
if c['file'] == current_value:
timelines_dropdown.text = c['name']
updating = false

View file

@ -4,6 +4,13 @@ extends EditorPlugin
var _editor_view
var _parts_inspector
func _init():
if Engine.editor_hint:
# Make sure the core files exist
DialogicResources.init_dialogic_files()
add_autoload_singleton('DialogicSingleton', "res://addons/dialogic/Other/DialogicSingleton.gd")
func _enter_tree() -> void:
_parts_inspector = load("res://addons/dialogic/Other/inspector_timeline_picker.gd").new()
add_inspector_plugin(_parts_inspector)
@ -14,8 +21,6 @@ func _enter_tree() -> void:
func _ready():
if Engine.editor_hint:
# Make sure the core files exist
DialogicResources.init_dialogic_files()
# Force Godot to show the dialogic folder
get_editor_interface().get_resource_filesystem().scan()