Fix dialogue manager plugin, lower resolution

This commit is contained in:
2025-06-27 18:53:08 -07:00
parent 338e303fbb
commit 39f791e2b4
43 changed files with 1565 additions and 856 deletions

View File

@@ -65,6 +65,8 @@ var _method_info_cache: Dictionary = {}
var _dotnet_dialogue_manager: RefCounted
var _expression_parser: DMExpressionParser = DMExpressionParser.new()
func _ready() -> void:
# Cache the known Node2D properties
@@ -185,6 +187,7 @@ func get_line(resource: DialogueResource, key: String, extra_game_states: Array)
continue
elif await _check_case_value(value, case, extra_game_states):
next_id = case.next_id
break
# Nothing matched so check for else case
if next_id == "":
if not else_case.is_empty():
@@ -206,16 +209,6 @@ func get_line(resource: DialogueResource, key: String, extra_game_states: Array)
else:
cummulative_weight += sibling.weight
# Find any simultaneously said lines.
var concurrent_lines: Array[DialogueLine] = []
if data.has(&"concurrent_lines"):
# If the list includes this line then it isn't the origin line so ignore it.
if not data.concurrent_lines.has(data.id):
for concurrent_id: String in data.concurrent_lines:
var concurrent_line: DialogueLine = await get_line(resource, concurrent_id, extra_game_states)
if concurrent_line:
concurrent_lines.append(concurrent_line)
# If this line is blank and it's the last line then check for returning snippets.
if data.type in [DMConstants.TYPE_COMMENT, DMConstants.TYPE_UNKNOWN]:
if data.next_id in [DMConstants.ID_END, DMConstants.ID_NULL, null]:
@@ -252,11 +245,18 @@ func get_line(resource: DialogueResource, key: String, extra_game_states: Array)
# Set up a line object.
var line: DialogueLine = await create_dialogue_line(data, extra_game_states)
line.concurrent_lines = concurrent_lines
# If the jump point somehow has no content then just end.
if not line: return null
# Find any simultaneously said lines.
if data.has(&"concurrent_lines"):
# If the list includes this line then it isn't the origin line so ignore it.
if not data.concurrent_lines.has(data.id):
# Resolve IDs to their actual lines.
for line_id: String in data.concurrent_lines:
line.concurrent_lines.append(await get_line(resource, line_id, extra_game_states))
# If we are the first of a list of responses then get the other ones.
if data.type == DMConstants.TYPE_RESPONSE:
# Note: For some reason C# has occasional issues with using the responses property directly
@@ -293,7 +293,15 @@ func get_resolved_line_data(data: Dictionary, extra_game_states: Array = []) ->
var text: String = translate(data)
# Resolve variables
for replacement in data.get(&"text_replacements", [] as Array[Dictionary]):
var text_replacements: Array[Dictionary] = data.get(&"text_replacements", [] as Array[Dictionary])
if text_replacements.size() == 0 and "{{" in text:
# This line is translated but has expressions that didn't exist in the base text.
text_replacements = _expression_parser.extract_replacements(text, 0)
for replacement in text_replacements:
if replacement.has("error"):
assert(false, "%s \"%s\"" % [DMConstants.get_error_message(replacement.get("error")), text])
var value = await _resolve(replacement.expression.duplicate(true), extra_game_states)
var index: int = text.find(replacement.value_in_text)
if index == -1:
@@ -442,6 +450,18 @@ func show_dialogue_balloon_scene(balloon_scene, resource: DialogueResource, titl
return balloon
## Resolve a static line ID to an actual line ID
func static_id_to_line_id(resource: DialogueResource, static_id: String) -> String:
var ids = static_id_to_line_ids(resource, static_id)
if ids.size() == 0: return ""
return ids[0]
## Resolve a static line ID to any actual line IDs that match
func static_id_to_line_ids(resource: DialogueResource, static_id: String) -> PackedStringArray:
return resource.lines.values().filter(func(l): return l.get(&"translation_key", "") == static_id).map(func(l): return l.id)
# Call "start" on the given balloon.
func _start_balloon(balloon: Node, resource: DialogueResource, title: String, extra_game_states: Array) -> void:
get_current_scene.call().add_child(balloon)
@@ -524,7 +544,7 @@ func show_error_for_missing_state_value(message: String, will_show: bool = true)
# Translate a string
func translate(data: Dictionary) -> String:
if translation_source == DMConstants.TranslationSource.None:
if TranslationServer.get_loaded_locales().size() == 0 or translation_source == DMConstants.TranslationSource.None:
return data.text
var translation_key: String = data.get(&"translation_key", data.text)
@@ -605,12 +625,13 @@ func create_response(data: Dictionary, extra_game_states: Array) -> DialogueResp
type = DMConstants.TYPE_RESPONSE,
next_id = data.next_id,
is_allowed = data.is_allowed,
condition_as_text = data.get(&"condition_as_text", ""),
character = await get_resolved_character(data, extra_game_states),
character_replacements = data.get(&"character_replacements", [] as Array[Dictionary]),
text = resolved_data.text,
text_replacements = data.get(&"text_replacements", [] as Array[Dictionary]),
tags = data.get(&"tags", []),
translation_key = data.get(&"translation_key", data.text)
translation_key = data.get(&"translation_key", data.text),
})
@@ -629,7 +650,7 @@ func _get_game_states(extra_game_states: Array) -> Array:
game_states = [_autoloads]
# Add any other state shortcuts from settings
for node_name in DMSettings.get_setting(DMSettings.STATE_AUTOLOAD_SHORTCUTS, ""):
var state: Node = Engine.get_main_loop().root.get_node_or_null(node_name)
var state: Node = Engine.get_main_loop().root.get_node_or_null(NodePath(node_name))
if state:
game_states.append(state)
@@ -661,21 +682,32 @@ func _check_case_value(match_value: Variant, data: Dictionary, extra_game_states
var expression: Array[Dictionary] = data.condition.expression.duplicate(true)
# If the when is a comparison when insert the match value as the first value to compare to
var already_compared: bool = false
if expression[0].type == DMConstants.TOKEN_COMPARISON:
expression.insert(0, {
type = DMConstants.TOKEN_VALUE,
value = match_value
})
already_compared = true
# Check for multiple values
var expressions_to_check: Array = []
var previous_comma_index: int = 0
for i in range(0, expression.size()):
if expression[i].type == DMConstants.TOKEN_COMMA:
expressions_to_check.append(expression.slice(previous_comma_index, i))
previous_comma_index = i + 1
elif i == expression.size() - 1:
expressions_to_check.append(expression.slice(previous_comma_index))
var resolved_value = await _resolve(expression, extra_game_states)
for expression_to_check in expressions_to_check:
# If the when is a comparison when insert the match value as the first value to compare to
var already_compared: bool = false
if expression_to_check[0].type == DMConstants.TOKEN_COMPARISON:
expression_to_check.insert(0, {
type = DMConstants.TOKEN_VALUE,
value = match_value
})
already_compared = true
var resolved_value = await _resolve(expression_to_check, extra_game_states)
if (already_compared and resolved_value) or match_value == resolved_value:
return true
return false
if already_compared:
return resolved_value
else:
return match_value == resolved_value
# Make a change to game state or run a method
@@ -757,6 +789,13 @@ func _get_state_value(property: String, extra_game_states: Array):
if state.has(property):
return state.get(property)
else:
# Try for a C# constant first
if state.get_script() \
and state.get_script().resource_path.ends_with(".cs") \
and _get_dotnet_dialogue_manager().ThingHasConstant(state, property):
return _get_dotnet_dialogue_manager().ResolveThingConstant(state, property)
# Otherwise just let Godot try and resolve it.
var result = expression.execute([], state, false)
if not expression.has_execute_failed():
return result
@@ -782,7 +821,7 @@ func _warn_about_state_name_collisions(target_key: String, extra_game_states: Ar
# Get the list of state shortcuts.
var state_shortcuts: Array = []
for node_name in DMSettings.get_setting(DMSettings.STATE_AUTOLOAD_SHORTCUTS, ""):
var state: Node = Engine.get_main_loop().root.get_node_or_null(node_name)
var state: Node = Engine.get_main_loop().root.get_node_or_null(NodePath(node_name))
if state:
state_shortcuts.append(state)
@@ -867,7 +906,18 @@ func _resolve(tokens: Array, extra_game_states: Array):
limit += 1
var token: Dictionary = tokens[i]
if token.type == DMConstants.TOKEN_FUNCTION:
if token.type == DMConstants.TOKEN_NULL_COALESCE:
var caller: Dictionary = tokens[i - 1]
if caller.value == null:
# If the caller is null then the method/property is also null
caller.type = DMConstants.TOKEN_VALUE
caller.value = null
tokens.remove_at(i + 1)
tokens.remove_at(i)
else:
token.type = DMConstants.TOKEN_DOT
elif token.type == DMConstants.TOKEN_FUNCTION:
var function_name: String = token.function
var args = await _resolve_each(token.value, extra_game_states)
if tokens[i - 1].type == DMConstants.TOKEN_DOT:
@@ -1330,6 +1380,9 @@ func _is_valid(line: DialogueLine) -> bool:
# Check that a thing has a given method.
func _thing_has_method(thing, method: String, args: Array) -> bool:
if not is_instance_valid(thing):
return false
if Builtins.is_supported(thing, method):
return thing != _autoloads
elif thing is Dictionary:
@@ -1344,7 +1397,7 @@ func _thing_has_method(thing, method: String, args: Array) -> bool:
if thing.has_method(method):
return true
if method.to_snake_case() != method and DMSettings.check_for_dotnet_solution():
if thing.get_script() and thing.get_script().resource_path.ends_with(".cs"):
# If we get this far then the method might be a C# method with a Task return type
return _get_dotnet_dialogue_manager().ThingHasMethod(thing, method, args)
@@ -1363,6 +1416,10 @@ func _thing_has_property(thing: Object, property: String) -> bool:
if p.name == property:
return true
if thing.get_script() and thing.get_script().resource_path.ends_with(".cs"):
# If we get this far then the property might be a C# constant.
return _get_dotnet_dialogue_manager().ThingHasConstant(thing, property)
return false