Repository navigation
Conversation
…n hashes A type-53 dialogue list pairs every cue definition, a hash and its authored duration, with a content tree sorted by hash. The tree is a sequence of children, a selection of conditioned entries, or a line holding two takes of the same text. Text extraction scanned the tree blob for container and string pairs and refused the whole list when two trees shared a hash, which left six missions, Homecoming among them, with no dialogue text. The list is now walked through its node classes, and each cue takes the one tree whose computed duration equals the authored one. A shared hash is logged, and a cue that cannot be matched keeps no lines while the rest of the list is still extracted. All 260 missions with dialogue cues now carry text.
Every cue of an authored type-53 list now has a row in a new dialogue cue
section: its definition hash, its authored duration in milliseconds, its line
count, and the list it was read from. The duration is present even when the
cue's content tree could not be matched; lines are only present when it was.
Line text rows carry their line and take index, audio tag and take duration,
and keep the order the lines play in.
Relation validation requires one row per cue for a slot that has any, and
text rows that name a line of their own cue. The generated mission Lua
publishes DialogueDefinition[cue] as { hash, duration_ms, lines }, and the host
dialogue view shows each cue's duration. Format version 39.
…duration A dialogue cue reaching the transport queue now raises dialogue_staged with the cue's type-53 source and the authored duration from the SDK cue row. Its dispatch arms a runtime timer named sunrise/dialogue/<slot row>/<cue>, even when the program has no handler for the event, and the timer service raises dialogue_finished instead of timer_elapsed when that timer comes due. Replaying a cue replaces its timer. A refused delivery stages nothing and arms nothing. The timer lives in durable mission state like any script timer, so it is restored and published with it. Scripts can no longer arm, cancel or read a timer whose name starts with sunrise/. A cue with no SDK cue row, or a full timer table, is logged and gets no timer.
0.5.0 reads the same counted definition array at +8 to bound a type-53 slot's cue count, so the list reader no longer parses it a second time. It now calls that reader and keeps only the tree walk, which means both paths accept exactly the same lists: a definition whose hash is absent, or a bank over the authored cue ceiling, is refused for the rows as it already is for the count.
Fozkais
force-pushed
the
sdk-dialogue-definitions
branch
from
September 18, 2026 00:57
d809656 to
08fce19
Compare
Contributor
Author
|
updated to match/adapt with 0.5.0 changes |
The dialogue cue row now starts with the same four fields the catalog already defines: slot, cue, definition hash and the authored window in seconds, validated the same way. List tag, line count and flags follow. Milliseconds are derived where they are needed, through one rounding helper: the Lua DialogueDefinition constants, the take durations of the text rows and the dialogue_staged event.
The page scanned every dialogue text row of the pack for each cue of an expanded sensor, and again from the start for each candidate it deduplicated. The text section now holds every take of every mission, so an expanded sensor cost tens of millions of row visits a frame and the game fell to 12 fps with the page open. Rows are written in slot, cue, line then take order; the relation check now requires it, and cue_dialogue_texts returns one cue's lines by binary search, as slot_dialogue_cues does for the cue rows. The two takes of a line are still shown once, compared inside that range only. The cue availability check reads the cue only against the slot's cue count, so it is resolved once per sensor instead of once per cue.
Fozkais
force-pushed
the
sdk-dialogue-definitions
branch
from
September 21, 2026 14:18
152f532 to
a33f359
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
dialogue_group_index::definitions, so the lines and the slot's cue count come from the same parse.dialogueCuessection with one row per cue of every dialogue slot. Each row keeps the catalog's slot, cue, definition hash and authored window in seconds, present even when the cue's tree was not matched, and adds the fields it has no reader for: source list, line count and flags. Text rows carry their line and take index, audio tag and take duration, and keep play order.mission.DialogueDefinition[cue] = { hash, duration_ms, lines }in the generated mission Lua, withDialogueCueVariantsin play order.on_event_dialogue_stagedwhen a cue reaches the transport queue andon_event_dialogue_finishedonce its authored duration has elapsed, from a runtime timer in durable mission state. The client reports nothing when a line ends, so a script had no way to wait for one.Files Modified
Pack Format
Sunrise/src/state/activity_sdk/format.hDialogueCueafter its slot, cue, definition hash andauthoredWindowSecondswith a string reference, the list tag, the line count and the flags; adds thekDialogueCueLinesExactflag. The section index is unchanged.DialogueCueTextgainslineIndex,takeIndex,audioTaganddurationMs; rows are ordered by slot, cue, line, then take.Sunrise/src/state/activity_sdk/activity_sdk_loader.cppSunrise/src/state/activity_sdk/generation/pack_writer.hSunrise/src/state/activity_sdk/generation/activity_sdk_pack_writer.cppSunrise/src/state/activity_sdk/runtime.hSunrise/src/state/activity_sdk/activity_sdk_catalog.cppCatalog::dialogue_cues()andslot_dialogue_cues(), which returns one contiguous range per type-53 slot, indexed by cue.authored_milliseconds(), the one rounding from authored seconds to milliseconds, saturating at 32 bits; the Lua constants, the text rows and the dialogue events use it.Sunrise/src/state/activity_sdk/activity_sdk_relation_validation.cppSunrise/src/state/activity_sdk/activity_sdk_structure_validation.cppdialogue_cuescheck: a type-53 slot with an exact cue count has either no cue row or exactly one per cue, in slot then cue order; flags are exact, the authored window is finite and not negative, and only a matched cue has lines. It replaces the cue loop insideauthored_text, which it covers.authored_textnow requires every text row to name an existing line of its own cue and a known take.SDK Generation
Sunrise/src/client/content/activity/activity_sdk_dialogue_list.hSunrise/src/client/content/activity/activity_sdk_dialogue_list.cpp0x80808D1D), selection (0x80808D1A, entries0x80808D1F) and line (0x80808D23) objects, with class checks at every step and bounds on depth, object count and array rows. Each cue gets aresolved,ambiguous,missingormalformedstatus.dialogue_group_index::definitions, which already parses that counted array for the slot's cue count, and keeps only the tree walk of its own. Both paths therefore accept exactly the same banks.Sunrise/src/client/content/activity/activity_sdk_native_pack_text.cppSunrise/src/client/content/activity/activity_sdk_native_pack_internal.hSunrise/src/client/content/activity/activity_sdk_native_pack_pipeline.cppev=activity_sdk_dialogue_listwith the descriptor context:shared_hashat info;malformed,cue_ambiguous,cue_missing,cue_malformed,list_conflictandcount_mismatchat warn. A list with no cue is skipped silently.attach_dialogue_cue_countskeeps bounding the slot's cue count and emits no cue row of its own, so one path fills the section.Sunrise/src/client/content/activity/activity_sdk_authored_scene_inventory.hSunrise/src/client/content/activity/activity_sdk_pack_composer.hSunrise/src/client/content/activity/activity_sdk_pack_composer.cppSunrise/src/client/content/activity/activity_sdk_pack_composer_rows.cppSunrise/src/client/content/activity/activity_sdk_pack_composer_validate.cppSunrise/src/client/content/activity/activity_sdk_lua_artifacts.hSunrise/src/client/content/activity/activity_sdk_lua_publish.cppSunrise/src/client/content/activity/activity_sdk_lua_activities.cppSunrise/src/client/content/activity/activity_sdk_lua_missions_internal.hSunrise/src/client/content/activity/activity_sdk_lua_missions.cppSunrise/src/client/content/activity/activity_sdk_lua_catalog_contract.cppSunrise/src/client/content/activity/activity_sdk_lua_contract.cppDialogueDefinitionfrom the cue rows withduration_msderived from the authored window, addCatalogDialogueCueViewand the new text row fields to the catalog contract, and count the section in the manifest.SunriseDialogueCueEvent,SunriseDialogueFinishedEvent, both handlers andDIALOGUE_STAGED/DIALOGUE_FINISHEDinEventKind.Mission Runtime
Sunrise/src/server/activity/host_runtime.hSunrise/src/server/activity/host_runtime_names.cppdialogueStaged(41) anddialogueFinished(42), afterregionChanged, neither a Host feed row, and the dialogue source, cue and duration fields onEvent.Sunrise/src/server/activity/mission/mission_script_runtime_delivery.cppSunrise/src/server/activity/mission/mission_script_runtime.cppSunrise/src/server/activity/mission/mission_script_runtime_internal.hplay_dialogue_cueintent is transport-staged, describe the cue from the bound catalog and queuedialogueStagedwithpush_program_event, which queues it whether or not the script handles it. A cue with no cue row is logged (dialogue cue_undefined) and gets no timer.dialogueFinishedinstead oftimerElapsedfor a runtime dialogue timer, and describes its source again from the catalog.Sunrise/src/server/activity/mission/mission_script_vm.hSunrise/src/server/activity/mission/mission_script_vm.cppdialogueStagedarms or replaces the timersunrise/dialogue/<slot row>/<cue>in the callback candidate, so it commits with the callback even without a handler;dialogueFinishedconsumes it astimerElapsedconsumes a script timer.timer_armed, and both handler names.Sunrise/src/server/activity/mission/mission_script_runtime_feed.cppdialogue timer_capacity), and names both kinds in the dispatch log lines.Sunrise/src/server/activity/mission/mission_script_lua_key_internal.hSunrise/src/server/activity/mission/mission_script_lua_state_api.cppSunrise/src/server/activity/mission/mission_script_lua_key_api.cppstart_timer,cancel_timer,state:timerandtimers:resolverefuse a name that starts withsunrise/.Sunrise/src/server/activity/mission/mission_script_lua_names.hSunrise/src/server/activity/mission/mission_script_lua_event_api.cppSunrise/src/server/activity/mission/mission_script_lua_event_derived.cppdialogue_registry_key,dialogue_slot_type,dialogue_slot_index,cue,duration_ms, and the timer members ondialogue_finished.Activity Host
Sunrise/src/server/ui/activity_host/activity_host_sdk_mission_view.cppValidation
29e6dbdpassed.08fce19, and again on the 10 files and 7 translation units29e6dbdtouches.0x80C2AF61, 94 cues): every definition's authored total equals the computed total of its tree, including the two cues that share0x0BF1BB31. Cue 0 was heard in game in the tree's line order.DialogueDefinitionentry per cue. Towerfall reads cue 0 = 15350 ms / 4 lines, cue 2 = 0 ms / 0 lines, cue 3 = 7728 ms / 1 line. The run logged 9shared_hashand 2cue_ambiguous(list0x80BD1E3B, cues 29 and 30), and nolist_conflict. It also logged 29count_mismatchfor the one empty list (0x80C23C8D), which led to skipping empty lists silently; the pack was not regenerated again after that change, nor after29e6dbd, which changes the row layout but not the values the rows carry.on_event_dialogue_finished. Staged-to-finished gaps were 15359, 3922, 2484, 0, 9172 and 3938 ms against 15350, 3933, 2500, 0, 9161 and 3933 authored, within the ~16 ms log tick. A 20 s script timer armed beside the chain fired astimer_elapsedon time. Nodialoguewarning and no mission fault were logged.Notes
DialogueDefinition[cue]was a bare hash and is now a table.dialogue_finishedis timed on it and scripts read it asduration_ms. If the field is both, the name exposed to scripts is the part to settle.dialogue_finishedfires after the authored total, which for a selection is its longest branch, so it can come after a shorter selected line has ended.sunrise/is now refused.list_conflictlogs the first list's tag in itsdefinition=field.format.h,activity_sdk_native_pack_text.cppand the Lua contract; whichever merges second takes the next version and rebases.