A DataTable can't show you a branch

The first version of quest data on Slime Slinger was a DataTable. It worked. The game read it, quests completed, the feature shipped in a milestone build. It also could not be read by a human being.

Branching is a graph. Storing a graph as rows means every reader has to rebuild the shape in their head, and every writer has to keep the row IDs consistent by hand. That is not a preference about tooling. It is a mismatch between data and representation, and mismatches get paid for in bugs, specifically the kind where a quest links to a step that does not exist and nobody notices until someone plays that branch.

What made it worth two months

A graph editor in Unreal is not a small job. There is a schema, a node factory, a toolkit, tab factories, asset type actions, a factory for creating the asset, thumbnail rendering, and a runtime module that must not depend on any of it. Most of that work is invisible when it is done right; it is what makes the asset feel native rather than bolted on. Nobody praises it. Everybody notices its absence.

The decision to spend that time came down to one question: how many quest changes will happen after this, and does each one need me? The answer was 'most of them' and 'yes', which made it arithmetic rather than a judgement call.

Validate while they author

The thing I would keep in any future version is that validation runs on connections as they are made, not behind a compile button. A wire that would produce an unreachable objective is refused at the moment the designer drags it.

The difference between validating on connect and validating on compile is the difference between a designer seeing a rejected wire and QA filing a ticket a fortnight later. Same check, same code, two orders of magnitude apart in what it costs to act on.

The best feature was the cheapest

Of everything in the plugin (the graph, the compiler pass, six objective types, sub-quests), the feature that saved the most time was this: selecting a GOTO node draws its acceptable radius in the level viewport.

Four functions behind a WITH_EDITOR guard. Before it, tuning a completion radius meant entering play, walking to the spot, seeing whether it triggered too early, exiting, changing a number, repeating. After it, you drag a value and watch a circle.

I have stopped being surprised by this. The highest-value tooling is usually not the architecturally interesting part; it is whatever removes a round trip from a loop somebody runs forty times a day. The graph compiler is the part I would put in a technical interview. The debug circle is the part that changed how the team worked.

What I'd change

Sub-quests were added late and they are the feature I would design differently. A quest that contains a quest is powerful and it makes the save-state versioning harder to reason about than it needs to be, because now a partially-complete objective can itself contain partially-complete objectives. It works, and there is a version stamp on saved progress so a content update cannot silently invalidate someone's file, but I would think harder about the state model before adding nesting again.