mirror of
https://gitlab.com/MaddoScientisto/cirnogodot.git
synced 2026-06-22 13:13:47 +00:00
Updated dialogic
This commit is contained in:
parent
1d11462073
commit
cbb82512ee
483 changed files with 5743 additions and 2177 deletions
|
|
@ -70,64 +70,71 @@ var paused := false:
|
|||
|
||||
dialogic_resumed.emit()
|
||||
|
||||
## A timeline that will be played when dialog ends.
|
||||
## By default this timeline only contains a clear event.
|
||||
var dialog_ending_timeline: DialogicTimeline
|
||||
|
||||
## Emitted when [member paused] changes to `true`.
|
||||
signal dialogic_paused
|
||||
## Emitted when [member paused] changes to `false`.
|
||||
signal dialogic_resumed
|
||||
|
||||
|
||||
## Emitted when the timeline ends.
|
||||
## This can be a timeline ending or [method end_timeline] being called.
|
||||
signal timeline_ended
|
||||
## Emitted when a timeline starts by calling either [method start]
|
||||
## or [method start_timeline].
|
||||
signal timeline_started
|
||||
## Emitted when the timeline ends.
|
||||
## This can be a timeline ending or [method end_timeline] being called.
|
||||
signal timeline_ended
|
||||
## Emitted when an event starts being executed.
|
||||
## The event may not have finished executing yet.
|
||||
signal event_handled(resource: DialogicEvent)
|
||||
|
||||
## Emitted when a [class SignalEvent] event was reached.
|
||||
@warning_ignore("unused_signal") # This is emitted by the signal event.
|
||||
signal signal_event(argument: Variant)
|
||||
|
||||
## Emitted when a signal event gets fired from a [class TextEvent] event.
|
||||
@warning_ignore("unused_signal") # This is emitted by the text subsystem.
|
||||
signal text_signal(argument: String)
|
||||
|
||||
|
||||
# Careful, this section is repopulated automatically at certain moments.
|
||||
#region SUBSYSTEMS
|
||||
|
||||
var Animations := preload("res://addons/dialogic/Modules/Core/subsystem_animation.gd").new():
|
||||
get: return get_subsystem("Animations")
|
||||
|
||||
var Audio := preload("res://addons/dialogic/Modules/Audio/subsystem_audio.gd").new():
|
||||
get: return get_subsystem("Audio")
|
||||
|
||||
var Backgrounds := preload("res://addons/dialogic/Modules/Background/subsystem_backgrounds.gd").new():
|
||||
get: return get_subsystem("Backgrounds")
|
||||
|
||||
var Portraits := preload("res://addons/dialogic/Modules/Character/subsystem_portraits.gd").new():
|
||||
get: return get_subsystem("Portraits")
|
||||
|
||||
var PortraitContainers := preload("res://addons/dialogic/Modules/Character/subsystem_containers.gd").new():
|
||||
get: return get_subsystem("PortraitContainers")
|
||||
|
||||
var Choices := preload("res://addons/dialogic/Modules/Choice/subsystem_choices.gd").new():
|
||||
get: return get_subsystem("Choices")
|
||||
|
||||
var Expressions := preload("res://addons/dialogic/Modules/Core/subsystem_expression.gd").new():
|
||||
get: return get_subsystem("Expressions")
|
||||
|
||||
var Animations := preload("res://addons/dialogic/Modules/Core/subsystem_animation.gd").new():
|
||||
get: return get_subsystem("Animations")
|
||||
|
||||
var Inputs := preload("res://addons/dialogic/Modules/Core/subsystem_input.gd").new():
|
||||
get: return get_subsystem("Inputs")
|
||||
|
||||
var Glossary := preload("res://addons/dialogic/Modules/Glossary/subsystem_glossary.gd").new():
|
||||
get: return get_subsystem("Glossary")
|
||||
|
||||
var History := preload("res://addons/dialogic/Modules/History/subsystem_history.gd").new():
|
||||
get: return get_subsystem("History")
|
||||
|
||||
var Inputs := preload("res://addons/dialogic/Modules/Core/subsystem_input.gd").new():
|
||||
get: return get_subsystem("Inputs")
|
||||
|
||||
var Jump := preload("res://addons/dialogic/Modules/Jump/subsystem_jump.gd").new():
|
||||
get: return get_subsystem("Jump")
|
||||
|
||||
var PortraitContainers := preload("res://addons/dialogic/Modules/Character/subsystem_containers.gd").new():
|
||||
get: return get_subsystem("PortraitContainers")
|
||||
|
||||
var Portraits := preload("res://addons/dialogic/Modules/Character/subsystem_portraits.gd").new():
|
||||
get: return get_subsystem("Portraits")
|
||||
|
||||
var Save := preload("res://addons/dialogic/Modules/Save/subsystem_save.gd").new():
|
||||
get: return get_subsystem("Save")
|
||||
|
||||
|
|
@ -149,9 +156,6 @@ var VAR := preload("res://addons/dialogic/Modules/Variable/subsystem_variables.g
|
|||
var Voice := preload("res://addons/dialogic/Modules/Voice/subsystem_voice.gd").new():
|
||||
get: return get_subsystem("Voice")
|
||||
|
||||
var ShowImage := preload("res://addons/dialogic_additions/ShowImage/subsystem_show_image.gd").new():
|
||||
get: return get_subsystem("ShowImage")
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
|
@ -161,6 +165,11 @@ func _ready() -> void:
|
|||
|
||||
clear()
|
||||
|
||||
DialogicResourceUtil.update_event_cache()
|
||||
|
||||
dialog_ending_timeline = DialogicTimeline.new()
|
||||
dialog_ending_timeline.from_text("[clear]")
|
||||
|
||||
|
||||
#region TIMELINE & EVENT HANDLING
|
||||
################################################################################
|
||||
|
|
@ -168,12 +177,12 @@ func _ready() -> void:
|
|||
## Method to start a timeline AND ensure that a layout scene is present.
|
||||
## For argument info, checkout [method start_timeline].
|
||||
## -> returns the layout node
|
||||
func start(timeline:Variant, label:Variant="") -> Node:
|
||||
func start(timeline:Variant, label_or_idx:Variant="") -> Node:
|
||||
# If we don't have a style subsystem, default to just start_timeline()
|
||||
if not has_subsystem('Styles'):
|
||||
printerr("[Dialogic] You called Dialogic.start() but the Styles subsystem is missing!")
|
||||
clear(ClearFlags.KEEP_VARIABLES)
|
||||
start_timeline(timeline, label)
|
||||
start_timeline(timeline, label_or_idx)
|
||||
return null
|
||||
|
||||
# Otherwise make sure there is a style active.
|
||||
|
|
@ -185,10 +194,12 @@ func start(timeline:Variant, label:Variant="") -> Node:
|
|||
scene.show()
|
||||
|
||||
if not scene.is_node_ready():
|
||||
scene.ready.connect(clear.bind(ClearFlags.KEEP_VARIABLES))
|
||||
scene.ready.connect(start_timeline.bind(timeline, label))
|
||||
if not scene.ready.is_connected(clear.bind(ClearFlags.KEEP_VARIABLES)):
|
||||
scene.ready.connect(clear.bind(ClearFlags.KEEP_VARIABLES))
|
||||
if not scene.ready.is_connected(start_timeline.bind(timeline, label_or_idx)):
|
||||
scene.ready.connect(start_timeline.bind(timeline, label_or_idx))
|
||||
else:
|
||||
start_timeline(timeline, label)
|
||||
start_timeline(timeline, label_or_idx)
|
||||
|
||||
return scene
|
||||
|
||||
|
|
@ -198,12 +209,12 @@ func start(timeline:Variant, label:Variant="") -> Node:
|
|||
## @label_or_idx can be a label (string) or index (int) to skip to immediatly.
|
||||
func start_timeline(timeline:Variant, label_or_idx:Variant = "") -> void:
|
||||
# load the resource if only the path is given
|
||||
if typeof(timeline) == TYPE_STRING:
|
||||
if typeof(timeline) in [TYPE_STRING, TYPE_STRING_NAME]:
|
||||
#check the lookup table if it's not a full file name
|
||||
if (timeline as String).contains("res://"):
|
||||
timeline = load((timeline as String))
|
||||
if "://" in timeline:
|
||||
timeline = load(timeline)
|
||||
else:
|
||||
timeline = DialogicResourceUtil.get_timeline_resource((timeline as String))
|
||||
timeline = DialogicResourceUtil.get_timeline_resource(timeline)
|
||||
|
||||
if timeline == null:
|
||||
printerr("[Dialogic] There was an error loading this timeline. Check the filename, and the timeline for errors")
|
||||
|
|
@ -217,7 +228,7 @@ func start_timeline(timeline:Variant, label_or_idx:Variant = "") -> void:
|
|||
event.dialogic = self
|
||||
current_event_idx = -1
|
||||
|
||||
if typeof(label_or_idx) == TYPE_STRING:
|
||||
if typeof(label_or_idx) in [TYPE_STRING, TYPE_STRING_NAME]:
|
||||
if label_or_idx:
|
||||
if has_subsystem('Jump'):
|
||||
Jump.jump_to_label((label_or_idx as String))
|
||||
|
|
@ -225,7 +236,9 @@ func start_timeline(timeline:Variant, label_or_idx:Variant = "") -> void:
|
|||
if label_or_idx >-1:
|
||||
current_event_idx = label_or_idx -1
|
||||
|
||||
timeline_started.emit()
|
||||
if not current_timeline == dialog_ending_timeline:
|
||||
timeline_started.emit()
|
||||
|
||||
handle_next_event()
|
||||
|
||||
|
||||
|
|
@ -233,8 +246,12 @@ func start_timeline(timeline:Variant, label_or_idx:Variant = "") -> void:
|
|||
## [param timeline_resource] can be either a path (string) or a loaded timeline (resource)
|
||||
func preload_timeline(timeline_resource:Variant) -> Variant:
|
||||
# I think ideally this should be on a new thread, will test
|
||||
if typeof(timeline_resource) == TYPE_STRING:
|
||||
timeline_resource = load((timeline_resource as String))
|
||||
if typeof(timeline_resource) in [TYPE_STRING, TYPE_STRING_NAME]:
|
||||
if "://" in timeline_resource:
|
||||
timeline_resource = load(timeline_resource)
|
||||
else:
|
||||
timeline_resource = DialogicResourceUtil.get_timeline_resource(timeline_resource)
|
||||
|
||||
if timeline_resource == null:
|
||||
printerr("[Dialogic] There was an error preloading this timeline. Check the filename, and the timeline for errors")
|
||||
return null
|
||||
|
|
@ -245,12 +262,37 @@ func preload_timeline(timeline_resource:Variant) -> Variant:
|
|||
|
||||
|
||||
## Clears and stops the current timeline.
|
||||
func end_timeline() -> void:
|
||||
## If [param skip_ending] is `true`, the dialog_ending_timeline is not getting played
|
||||
func end_timeline(skip_ending := false) -> void:
|
||||
if not skip_ending and dialog_ending_timeline and current_timeline != dialog_ending_timeline:
|
||||
start(dialog_ending_timeline)
|
||||
return
|
||||
|
||||
await clear(ClearFlags.TIMELINE_INFO_ONLY)
|
||||
_on_timeline_ended()
|
||||
|
||||
if Styles.has_active_layout_node() and Styles.get_layout_node().is_inside_tree():
|
||||
match ProjectSettings.get_setting('dialogic/layout/end_behaviour', 0):
|
||||
0:
|
||||
Styles.get_layout_node().get_parent().remove_child(Styles.get_layout_node())
|
||||
Styles.get_layout_node().queue_free()
|
||||
1:
|
||||
Styles.get_layout_node().hide()
|
||||
|
||||
timeline_ended.emit()
|
||||
|
||||
|
||||
## Method to check if timeline exists.
|
||||
## @timeline can be either a loaded timeline resource or a path to a timeline file.
|
||||
func timeline_exists(timeline:Variant) -> bool:
|
||||
if typeof(timeline) in [TYPE_STRING, TYPE_STRING_NAME]:
|
||||
if "://" in timeline and ResourceLoader.exists(timeline):
|
||||
return load(timeline) is DialogicTimeline
|
||||
else:
|
||||
return DialogicResourceUtil.timeline_resource_exists(timeline)
|
||||
|
||||
return timeline is DialogicTimeline
|
||||
|
||||
|
||||
## Handles the next event.
|
||||
func handle_next_event(_ignore_argument: Variant = "") -> void:
|
||||
handle_event(current_event_idx+1)
|
||||
|
|
@ -271,6 +313,7 @@ func handle_event(event_index:int) -> void:
|
|||
end_timeline()
|
||||
return
|
||||
|
||||
# TODO: Check if necessary. This should be impossible.
|
||||
#actually process the event now, since we didnt earlier at runtime
|
||||
#this needs to happen before we create the copy DialogicEvent variable, so it doesn't throw an error if not ready
|
||||
if current_timeline_events[event_index].event_node_ready == false:
|
||||
|
|
@ -370,7 +413,7 @@ func load_full_state(state_info:Dictionary) -> void:
|
|||
if current_state_info.get('current_timeline', null):
|
||||
start_timeline(current_state_info.current_timeline, current_state_info.get('current_event_idx', 0))
|
||||
else:
|
||||
end_timeline.call_deferred()
|
||||
end_timeline.call_deferred(true)
|
||||
#endregion
|
||||
|
||||
|
||||
|
|
@ -415,22 +458,12 @@ func add_subsystem(subsystem_name:String, script_path:String) -> DialogicSubsyst
|
|||
#region HELPERS
|
||||
################################################################################
|
||||
|
||||
## This handles the `Layout End Behaviour` setting that can be changed in the Dialogic settings.
|
||||
func _on_timeline_ended() -> void:
|
||||
if self.Styles.has_active_layout_node() and self.Styles.get_layout_node().is_inside_tree():
|
||||
match ProjectSettings.get_setting('dialogic/layout/end_behaviour', 0):
|
||||
0:
|
||||
self.Styles.get_layout_node().get_parent().remove_child(self.Styles.get_layout_node())
|
||||
self.Styles.get_layout_node().queue_free()
|
||||
1:
|
||||
@warning_ignore("unsafe_method_access")
|
||||
self.Styles.get_layout_node().hide()
|
||||
|
||||
|
||||
func print_debug_moment() -> void:
|
||||
if not current_timeline:
|
||||
return
|
||||
|
||||
printerr("\tAt event ", current_event_idx+1, " (",current_timeline_events[current_event_idx].event_name, ' Event) in timeline "', DialogicResourceUtil.get_unique_identifier(current_timeline.resource_path), '" (',current_timeline.resource_path,').')
|
||||
printerr("\tAt event ", current_event_idx+1, " (",current_timeline_events[current_event_idx].event_name, ' Event) in timeline "', current_timeline.get_identifier(), '" (',current_timeline.resource_path,').')
|
||||
print("\n")
|
||||
#endregion
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
uid://dwg1hpegqijbk
|
||||
uid://ds2q0uclmolvu
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ class_name DialogicResourceUtil
|
|||
|
||||
static var label_cache := {}
|
||||
static var event_cache: Array[DialogicEvent] = []
|
||||
static var channel_cache := {}
|
||||
|
||||
static var special_resources := {}
|
||||
|
||||
|
|
@ -11,6 +12,8 @@ static func update() -> void:
|
|||
update_directory('.dch')
|
||||
update_directory('.dtl')
|
||||
update_label_cache()
|
||||
update_audio_channel_cache()
|
||||
DialogicStylesUtil.build_style_directory()
|
||||
|
||||
|
||||
#region RESOURCE DIRECTORIES
|
||||
|
|
@ -53,30 +56,54 @@ static func update_directory(extension:String) -> void:
|
|||
|
||||
static func add_resource_to_directory(file_path:String, directory:Dictionary) -> Dictionary:
|
||||
var suggested_name := file_path.get_file().trim_suffix("."+file_path.get_extension())
|
||||
var temp := suggested_name
|
||||
while suggested_name in directory:
|
||||
suggested_name = file_path.trim_suffix("/"+suggested_name+"."+file_path.get_extension()).get_file().path_join(suggested_name)
|
||||
if suggested_name == temp:
|
||||
break
|
||||
temp = suggested_name
|
||||
directory[suggested_name] = file_path
|
||||
return directory
|
||||
|
||||
|
||||
## Returns the unique identifier for the given resource path.
|
||||
## Returns an empty string if no identifier was found.
|
||||
static func get_unique_identifier(file_path:String) -> String:
|
||||
var identifier: String = get_directory(file_path.get_extension()).find_key(file_path)
|
||||
static func get_unique_identifier_by_path(file_path:String) -> String:
|
||||
if not file_path: return ""
|
||||
var identifier: Variant = get_directory(file_path.get_extension()).find_key(file_path)
|
||||
if typeof(identifier) == TYPE_STRING:
|
||||
return identifier
|
||||
return ""
|
||||
|
||||
|
||||
static func get_resource_path_from_identifier(identifier:String, extension:String) -> String:
|
||||
var value: Variant = get_directory(extension).get(identifier, '')
|
||||
if value is String:
|
||||
return value
|
||||
return ""
|
||||
|
||||
|
||||
## Returns the resource associated with the given unique identifier.
|
||||
## The expected extension is needed to use the right directory.
|
||||
static func get_resource_from_identifier(identifier:String, extension:String) -> Resource:
|
||||
var path: String = get_directory(extension).get(identifier, '')
|
||||
if ResourceLoader.exists(path):
|
||||
return load(path)
|
||||
var value: Variant = get_directory(extension).get(identifier, '')
|
||||
if typeof(value) == TYPE_STRING and ResourceLoader.exists(value):
|
||||
return load(value)
|
||||
elif value is Resource:
|
||||
return value
|
||||
return null
|
||||
|
||||
|
||||
## Returns a boolean that expresses whether the resource exists.
|
||||
## The expected extension is needed to use the right directory.
|
||||
static func resource_exists_from_identifier(identifier:String, extension:String) -> bool:
|
||||
var value: Variant = get_directory(extension).get(identifier, '')
|
||||
if typeof(value) == TYPE_STRING:
|
||||
return ResourceLoader.exists(value)
|
||||
return value is Resource
|
||||
|
||||
|
||||
## Editor Only
|
||||
static func change_unique_identifier(file_path:String, new_identifier:String) -> void:
|
||||
var directory := get_directory(file_path.get_extension())
|
||||
var key: String = directory.find_key(file_path)
|
||||
|
|
@ -110,6 +137,21 @@ static func remove_resource(file_path:String) -> void:
|
|||
static func is_identifier_unused(extension:String, identifier:String) -> bool:
|
||||
return not identifier in get_directory(extension)
|
||||
|
||||
|
||||
## While usually the directory maps identifiers to paths, this method (only supposed to be used at runtime)
|
||||
## allows mapping resources that are not saved to an identifier.
|
||||
static func register_runtime_resource(resource:Resource, identifier:String, extension:String) -> void:
|
||||
var directory := get_directory(extension)
|
||||
directory[identifier] = resource
|
||||
set_directory(extension, directory)
|
||||
|
||||
|
||||
static func get_runtime_unique_identifier(resource:Resource, extension:String) -> String:
|
||||
var identifier: Variant = get_directory(extension).find_key(resource)
|
||||
if typeof(identifier) == TYPE_STRING:
|
||||
return identifier
|
||||
return ""
|
||||
|
||||
#endregion
|
||||
|
||||
#region LABEL CACHE
|
||||
|
|
@ -139,6 +181,45 @@ static func update_label_cache() -> void:
|
|||
|
||||
#endregion
|
||||
|
||||
#region AUDIO CHANNEL CACHE
|
||||
################################################################################
|
||||
# The audio channel cache is only for the editor so we don't have to scan all timelines
|
||||
# whenever we want to suggest channels. This has no use in game and is not always perfect.
|
||||
|
||||
static func get_audio_channel_cache() -> Dictionary:
|
||||
if not channel_cache.is_empty():
|
||||
return channel_cache
|
||||
|
||||
channel_cache = DialogicUtil.get_editor_setting('channel_ref', {})
|
||||
return channel_cache
|
||||
|
||||
|
||||
static func get_channel_list() -> Array:
|
||||
if channel_cache.is_empty():
|
||||
return []
|
||||
|
||||
var cached_names := []
|
||||
for timeline in channel_cache:
|
||||
for name in channel_cache[timeline]:
|
||||
if not cached_names.has(name):
|
||||
cached_names.append(name)
|
||||
return cached_names
|
||||
|
||||
|
||||
static func set_audio_channel_cache(cache:Dictionary) -> void:
|
||||
channel_cache = cache
|
||||
|
||||
|
||||
static func update_audio_channel_cache() -> void:
|
||||
var cache := get_audio_channel_cache()
|
||||
var timelines := get_timeline_directory().values()
|
||||
for timeline in cache:
|
||||
if !timeline in timelines:
|
||||
cache.erase(timeline)
|
||||
set_audio_channel_cache(cache)
|
||||
|
||||
#endregion
|
||||
|
||||
#region EVENT CACHE
|
||||
################################################################################
|
||||
|
||||
|
|
@ -260,6 +341,10 @@ static func get_timeline_directory() -> Dictionary:
|
|||
return get_directory('dtl')
|
||||
|
||||
|
||||
static func timeline_resource_exists(timeline_identifier:String) -> bool:
|
||||
return resource_exists_from_identifier(timeline_identifier, 'dtl')
|
||||
|
||||
|
||||
static func get_timeline_resource(timeline_identifier:String) -> DialogicTimeline:
|
||||
return get_resource_from_identifier(timeline_identifier, 'dtl')
|
||||
|
||||
|
|
@ -275,7 +360,7 @@ static func list_resources_of_type(extension:String) -> Array:
|
|||
|
||||
static func scan_folder(path:String, extension:String) -> Array:
|
||||
var list: Array = []
|
||||
if DirAccess.dir_exists_absolute(path):
|
||||
if DirAccess.dir_exists_absolute(path) and not FileAccess.file_exists(path + "/" + ".gdignore"):
|
||||
var dir := DirAccess.open(path)
|
||||
dir.list_dir_begin()
|
||||
var file_name := dir.get_next()
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
uid://dsn41e1wjwfp4
|
||||
uid://bdt5bbxxkvab4
|
||||
|
|
|
|||
|
|
@ -9,7 +9,9 @@ class_name DialogicUtil
|
|||
## This method should be used instead of EditorInterface.get_editor_scale(), because if you use that
|
||||
## it will run perfectly fine from the editor, but crash when the game is exported.
|
||||
static func get_editor_scale() -> float:
|
||||
return get_dialogic_plugin().get_editor_interface().get_editor_scale()
|
||||
if Engine.is_editor_hint():
|
||||
return get_dialogic_plugin().get_editor_interface().get_editor_scale()
|
||||
return 1.0
|
||||
|
||||
|
||||
## Although this does in fact always return a EditorPlugin node,
|
||||
|
|
@ -77,11 +79,19 @@ static func _update_autoload_subsystem_access() -> void:
|
|||
|
||||
var script: Script = load("res://addons/dialogic/Core/DialogicGameHandler.gd")
|
||||
var new_subsystem_access_list := "#region SUBSYSTEMS\n"
|
||||
var subsystems_sorted := []
|
||||
|
||||
for indexer: DialogicIndexer in get_indexers(true, true):
|
||||
|
||||
for subsystem: Dictionary in indexer._get_subsystems().duplicate(true):
|
||||
new_subsystem_access_list += '\nvar {name} := preload("{script}").new():\n\tget: return get_subsystem("{name}")\n'.format(subsystem)
|
||||
subsystems_sorted.append(subsystem)
|
||||
|
||||
subsystems_sorted.sort_custom(func (a: Dictionary, b: Dictionary) -> bool:
|
||||
return a.name < b.name
|
||||
)
|
||||
|
||||
for subsystem: Dictionary in subsystems_sorted:
|
||||
new_subsystem_access_list += '\nvar {name} := preload("{script}").new():\n\tget: return get_subsystem("{name}")\n'.format(subsystem)
|
||||
|
||||
new_subsystem_access_list += "\n#endregion"
|
||||
script.source_code = RegEx.create_from_string(r"#region SUBSYSTEMS\n#*\n((?!#endregion)(.*\n))*#endregion").sub(script.source_code, new_subsystem_access_list)
|
||||
|
|
@ -90,11 +100,10 @@ static func _update_autoload_subsystem_access() -> void:
|
|||
|
||||
|
||||
static func get_indexers(include_custom := true, force_reload := false) -> Array[DialogicIndexer]:
|
||||
if Engine.get_main_loop().has_meta('dialogic_indexers') and !force_reload:
|
||||
if Engine.get_main_loop().has_meta('dialogic_indexers') and not force_reload:
|
||||
return Engine.get_main_loop().get_meta('dialogic_indexers')
|
||||
|
||||
var indexers: Array[DialogicIndexer] = []
|
||||
|
||||
for file in listdir(DialogicUtil.get_module_path(''), false):
|
||||
var possible_script: String = DialogicUtil.get_module_path(file).path_join("index.gd")
|
||||
if ResourceLoader.exists(possible_script):
|
||||
|
|
@ -287,40 +296,6 @@ static func _get_value_in_dictionary(path:String, dictionary:Dictionary, default
|
|||
#endregion
|
||||
|
||||
|
||||
|
||||
#region STYLES
|
||||
################################################################################
|
||||
|
||||
static func get_default_layout_base() -> PackedScene:
|
||||
return load(DialogicUtil.get_module_path('DefaultLayoutParts').path_join("Base_Default/default_layout_base.tscn"))
|
||||
|
||||
|
||||
static func get_fallback_style() -> DialogicStyle:
|
||||
return load(DialogicUtil.get_module_path('DefaultLayoutParts').path_join("Style_VN_Default/default_vn_style.tres"))
|
||||
|
||||
|
||||
static func get_default_style() -> DialogicStyle:
|
||||
var default: String = ProjectSettings.get_setting('dialogic/layout/default_style', '')
|
||||
if !ResourceLoader.exists(default):
|
||||
return get_fallback_style()
|
||||
return load(default)
|
||||
|
||||
|
||||
static func get_style_by_name(name:String) -> DialogicStyle:
|
||||
if name.is_empty():
|
||||
return get_default_style()
|
||||
|
||||
var styles: Array = ProjectSettings.get_setting('dialogic/layout/style_list', [])
|
||||
for style in styles:
|
||||
if not ResourceLoader.exists(style):
|
||||
continue
|
||||
if load(style).name == name:
|
||||
return load(style)
|
||||
|
||||
return get_default_style()
|
||||
#endregion
|
||||
|
||||
|
||||
#region SCENE EXPORT OVERRIDES
|
||||
################################################################################
|
||||
|
||||
|
|
@ -458,39 +433,53 @@ static func setup_script_property_edit_node(property_info: Dictionary, value:Var
|
|||
input.select(value)
|
||||
input.item_selected.connect(DialogicUtil._on_export_int_enum_submitted.bind(property_info.name, property_changed))
|
||||
else:
|
||||
input = SpinBox.new()
|
||||
input.value_changed.connect(DialogicUtil._on_export_number_submitted.bind(property_info.name, property_changed))
|
||||
if property_info.hint_string == 'int':
|
||||
input.step = 1
|
||||
input.allow_greater = true
|
||||
input.allow_lesser = true
|
||||
elif ',' in property_info.hint_string:
|
||||
input = load("res://addons/dialogic/Editor/Events/Fields/field_number.tscn").instantiate()
|
||||
input.property_name = property_info['name']
|
||||
input.use_int_mode()
|
||||
|
||||
if ',' in property_info.hint_string:
|
||||
input.min_value = int(property_info.hint_string.get_slice(',', 0))
|
||||
input.max_value = int(property_info.hint_string.get_slice(',', 1))
|
||||
if property_info.hint_string.count(',') > 1:
|
||||
input.step = int(property_info.hint_string.get_slice(',', 2))
|
||||
else:
|
||||
input.step = 1
|
||||
input.max_value = INF
|
||||
input.min_value = -INF
|
||||
|
||||
if value != null:
|
||||
input.value = value
|
||||
input.set_value(value)
|
||||
input.value_changed.connect(DialogicUtil._on_export_number_submitted.bind(property_changed))
|
||||
TYPE_FLOAT:
|
||||
input = SpinBox.new()
|
||||
input = load("res://addons/dialogic/Editor/Events/Fields/field_number.tscn").instantiate()
|
||||
input.property_name = property_info['name']
|
||||
input.use_float_mode()
|
||||
input.step = 0.01
|
||||
if ',' in property_info.hint_string:
|
||||
input.min_value = float(property_info.hint_string.get_slice(',', 0))
|
||||
input.max_value = float(property_info.hint_string.get_slice(',', 1))
|
||||
if property_info.hint_string.count(',') > 1:
|
||||
input.step = float(property_info.hint_string.get_slice(',', 2))
|
||||
input.value_changed.connect(DialogicUtil._on_export_number_submitted.bind(property_info.name, property_changed))
|
||||
if value != null:
|
||||
input.value = value
|
||||
input.set_value(value)
|
||||
input.value_changed.connect(DialogicUtil._on_export_number_submitted.bind(property_changed))
|
||||
TYPE_VECTOR2, TYPE_VECTOR3, TYPE_VECTOR4:
|
||||
var vectorSize: String = type_string(typeof(value))[-1]
|
||||
input = load("res://addons/dialogic/Editor/Events/Fields/field_vector" + vectorSize + ".tscn").instantiate()
|
||||
input.property_name = property_info['name']
|
||||
input.set_value(value)
|
||||
input.value_changed.connect(DialogicUtil._on_export_vector_submitted.bind(property_changed))
|
||||
TYPE_VECTOR2I, TYPE_VECTOR3I, TYPE_VECTOR4I:
|
||||
var vectorSize: String = type_string(typeof(value))[-2]
|
||||
input = load("res://addons/dialogic/Editor/Events/Fields/field_vector" + vectorSize + ".tscn").instantiate()
|
||||
input.step = 1
|
||||
input.property_name = property_info['name']
|
||||
input.set_value(value)
|
||||
input.value_changed.connect(DialogicUtil._on_export_vectori_submitted.bind(property_changed))
|
||||
TYPE_STRING:
|
||||
if property_info['hint'] & PROPERTY_HINT_FILE or property_info['hint'] & PROPERTY_HINT_DIR:
|
||||
input = load("res://addons/dialogic/Editor/Events/Fields/field_file.tscn").instantiate()
|
||||
input.show_editing_button = true
|
||||
input.file_filter = property_info['hint_string']
|
||||
input.file_mode = FileDialog.FILE_MODE_OPEN_FILE
|
||||
if property_info['hint'] == PROPERTY_HINT_DIR:
|
||||
|
|
@ -518,6 +507,7 @@ static func setup_script_property_edit_node(property_info: Dictionary, value:Var
|
|||
TYPE_DICTIONARY:
|
||||
input = load("res://addons/dialogic/Editor/Events/Fields/field_dictionary.tscn").instantiate()
|
||||
input.property_name = property_info["name"]
|
||||
input.set_value(value)
|
||||
input.value_changed.connect(_on_export_dict_submitted.bind(property_changed))
|
||||
TYPE_OBJECT:
|
||||
input = load("res://addons/dialogic/Editor/Common/hint_tooltip_icon.tscn").instantiate()
|
||||
|
|
@ -543,7 +533,7 @@ static func _on_export_color_submitted(color:Color, property_name:String, callab
|
|||
static func _on_export_int_enum_submitted(item:int, property_name:String, callable: Callable) -> void:
|
||||
callable.call(property_name, var_to_str(item))
|
||||
|
||||
static func _on_export_number_submitted(value:float, property_name:String, callable: Callable) -> void:
|
||||
static func _on_export_number_submitted(property_name:String, value:float, callable: Callable) -> void:
|
||||
callable.call(property_name, var_to_str(value))
|
||||
|
||||
static func _on_export_file_submitted(property_name:String, value:String, callable: Callable) -> void:
|
||||
|
|
@ -555,6 +545,13 @@ static func _on_export_string_enum_submitted(value:int, property_name:String, li
|
|||
static func _on_export_vector_submitted(property_name:String, value:Variant, callable: Callable) -> void:
|
||||
callable.call(property_name, var_to_str(value))
|
||||
|
||||
static func _on_export_vectori_submitted(property_name:String, value:Variant, callable: Callable) -> void:
|
||||
match typeof(value):
|
||||
TYPE_VECTOR2: value = Vector2i(value)
|
||||
TYPE_VECTOR3: value = Vector3i(value)
|
||||
TYPE_VECTOR4: value = Vector4i(value)
|
||||
callable.call(property_name, var_to_str(value))
|
||||
|
||||
static func _on_export_dict_submitted(property_name:String, value:Variant, callable: Callable) -> void:
|
||||
callable.call(property_name, var_to_str(value))
|
||||
|
||||
|
|
@ -674,3 +671,133 @@ static func get_portrait_position_suggestions(search_text := "") -> Dictionary:
|
|||
suggestions.erase(search_text)
|
||||
|
||||
return suggestions
|
||||
|
||||
|
||||
static func get_autoload_suggestions(filter:String="") -> Dictionary:
|
||||
var suggestions := {}
|
||||
|
||||
for prop in ProjectSettings.get_property_list():
|
||||
if prop.name.begins_with('autoload/'):
|
||||
var some_autoload: String = prop.name.trim_prefix('autoload/')
|
||||
suggestions[some_autoload] = {'value': some_autoload, 'tooltip':some_autoload, 'editor_icon': ["Node", "EditorIcons"]}
|
||||
if filter.begins_with(some_autoload):
|
||||
suggestions[filter] = {'value': filter, 'editor_icon':["GuiScrollArrowRight", "EditorIcons"]}
|
||||
return suggestions
|
||||
|
||||
|
||||
static func get_autoload_script_resource(autoload_name:String) -> Script:
|
||||
var script: Script
|
||||
if autoload_name and ProjectSettings.has_setting('autoload/'+autoload_name):
|
||||
var loaded_autoload := load(ProjectSettings.get_setting('autoload/'+autoload_name).trim_prefix('*'))
|
||||
|
||||
if loaded_autoload is PackedScene:
|
||||
var packed_scene: PackedScene = loaded_autoload
|
||||
script = packed_scene.instantiate().get_script()
|
||||
|
||||
else:
|
||||
script = loaded_autoload
|
||||
return script
|
||||
|
||||
|
||||
static func get_autoload_method_suggestions(filter:String, autoload_name:String) -> Dictionary:
|
||||
var suggestions := {}
|
||||
|
||||
var script := get_autoload_script_resource(autoload_name)
|
||||
if script:
|
||||
for script_method in script.get_script_method_list():
|
||||
if script_method.name.begins_with('@') or script_method.name.begins_with('_'):
|
||||
continue
|
||||
suggestions[script_method.name] = {'value': script_method.name, 'tooltip':script_method.name, 'editor_icon': ["Callable", "EditorIcons"]}
|
||||
|
||||
if not filter.is_empty():
|
||||
suggestions[filter] = {'value': filter, 'editor_icon':["GuiScrollArrowRight", "EditorIcons"]}
|
||||
|
||||
return suggestions
|
||||
|
||||
|
||||
static func get_autoload_property_suggestions(_filter:String, autoload_name:String) -> Dictionary:
|
||||
var suggestions := {}
|
||||
var script := get_autoload_script_resource(autoload_name)
|
||||
if script:
|
||||
for property in script.get_script_property_list():
|
||||
if property.name.ends_with('.gd') or property.name.begins_with('_'):
|
||||
continue
|
||||
suggestions[property.name] = {'value': property.name, 'tooltip':property.name, 'editor_icon': ["MemberProperty", "EditorIcons"]}
|
||||
|
||||
return suggestions
|
||||
|
||||
|
||||
static func get_audio_bus_suggestions(_filter:= "") -> Dictionary:
|
||||
var bus_name_list := {}
|
||||
for i in range(AudioServer.bus_count):
|
||||
if i == 0:
|
||||
bus_name_list[AudioServer.get_bus_name(i)] = {'value':''}
|
||||
else:
|
||||
bus_name_list[AudioServer.get_bus_name(i)] = {'value':AudioServer.get_bus_name(i)}
|
||||
return bus_name_list
|
||||
|
||||
|
||||
static func get_audio_channel_suggestions(_search_text:String) -> Dictionary:
|
||||
var suggestions := {}
|
||||
var channel_defaults := DialogicUtil.get_audio_channel_defaults()
|
||||
var cached_names := DialogicResourceUtil.get_channel_list()
|
||||
|
||||
for i in channel_defaults.keys():
|
||||
if not cached_names.has(i):
|
||||
cached_names.append(i)
|
||||
|
||||
cached_names.sort()
|
||||
|
||||
for i in cached_names:
|
||||
if i.is_empty():
|
||||
continue
|
||||
|
||||
suggestions[i] = {'value': i}
|
||||
|
||||
if i in channel_defaults.keys():
|
||||
suggestions[i]["editor_icon"] = ["ProjectList", "EditorIcons"]
|
||||
suggestions[i]["tooltip"] = "A default channel defined in the settings."
|
||||
|
||||
else:
|
||||
suggestions[i]["editor_icon"] = ["AudioStreamPlayer", "EditorIcons"]
|
||||
suggestions[i]["tooltip"] = "A temporary channel without defaults."
|
||||
|
||||
return suggestions
|
||||
|
||||
|
||||
static func get_audio_channel_defaults() -> Dictionary:
|
||||
return ProjectSettings.get_setting('dialogic/audio/channel_defaults', {
|
||||
"": {
|
||||
'volume': 0.0,
|
||||
'audio_bus': '',
|
||||
'fade_length': 0.0,
|
||||
'loop': false,
|
||||
},
|
||||
"music": {
|
||||
'volume': 0.0,
|
||||
'audio_bus': '',
|
||||
'fade_length': 0.0,
|
||||
'loop': true,
|
||||
}})
|
||||
|
||||
|
||||
static func validate_audio_channel_name(text: String) -> Dictionary:
|
||||
var result := {}
|
||||
var channel_name_regex := RegEx.create_from_string(r'(?<dash_only>^-$)|(?<invalid>[^\w-]{1})')
|
||||
var matches := channel_name_regex.search_all(text)
|
||||
var invalid_chars := []
|
||||
|
||||
for regex_match in matches:
|
||||
if regex_match.get_string('dash_only'):
|
||||
result['error_tooltip'] = "Channel name cannot be '-'."
|
||||
result['valid_text'] = ''
|
||||
else:
|
||||
var invalid_char = regex_match.get_string('invalid')
|
||||
if not invalid_char in invalid_chars:
|
||||
invalid_chars.append(invalid_char)
|
||||
|
||||
if invalid_chars:
|
||||
result['valid_text'] = channel_name_regex.sub(text, '', true)
|
||||
result['error_tooltip'] = "Channel names cannot contain the following characters: " + "".join(invalid_chars)
|
||||
|
||||
return result
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
uid://7bp2a34fvy0d
|
||||
uid://c848iwoo6mnms
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
uid://b7qj1lgysmwlc
|
||||
uid://d4iojsqnbdphm
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ func list_dir(subdir:='') -> Array:
|
|||
func list_special_resources(subdir:='', extension:="") -> Dictionary:
|
||||
var dict := {}
|
||||
for i in list_dir(subdir):
|
||||
if extension.is_empty() or i.ends_with(extension):
|
||||
if extension.is_empty() or i.ends_with(extension) or (extension == ".gd" and i.ends_with(".gdc")):
|
||||
dict[DialogicUtil.pretty_name(i).to_lower()] = {"path":i}
|
||||
return dict
|
||||
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
uid://d06pvy04nmmby
|
||||
uid://ciwsx3rjhhmg7
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue