After last night's post, I figured out what I was doing wrong: I had two arguments in the wrong order. When I swapped them, it worked fine.
Before I touch anything else, I want to figure out what is in the StoryState class that I care about. I'm going to do that in here. Fair warning: I don't really know .NET or C#, so I'm going to be playing fast and loose with some of the terminology.
All right, so the following attributes get touched inside the Copy method:
- outputStream (manipulating this appears to also involve OutputStreamDirty()); this is a getter around _outputStream.
- _currentChoices; this is a variable.
- hasError and currentErrors; hasError is free in Python, syntactically speaking, and currentErrors is a semi-protected variable.
- callStack and _originalCallstack; callStack is a variable, and _originalCallstack is a slot that's needed for some function calls or something.
- variablesState (which has stuff to do with callStack and story.listDefinitions); variablesState is a variable.
- evaluationStack and _originalEvaluationStackHeight; evaluationStack is a semi-protected variable and _originalEvaluationStackHeight is another sometimes-needed thing.
- divertedTargetObject; this is a variable.
- previousContentObject; this is a calculated value that lives in the callStack, so I'm not entirely sure why Copy is setting it explicitly when it should, just... have the right value because the callStack gets copied...
- visitCounts; this is a semi-protected variable.
- turnIndices; this is a semi-protected variable.
- currentTurnIndex; this is a semi-protected variable.
- storySeed; this is a variable.
- previousRandom; this is a variable.
- didSafeExit; this is a variable.
In the jsonToken property, we get...
- _currentChoices (above)
- callStack (above)
- choiceThreads isn't an attribute, rather it's derived from _currentChoices and callStack
- callStack (above)
- variablesState (above)
- evaluationStack (above, though I got thrown off for a sec because the serialization names don't match the variable names for... some reason)
- _outputStream (above)
- divertedTargetObject (above)
- visitCounts (above)
- turnIndices (above)
- currentTurnIndex (above)
- storySeed (above)
- previousRandom (above)
- didSafeExit is not in there, that I see
Now, I came up with the idea to divide the StoryState behavior into three (now four) states: LineState, ChoiceState, ReadyState, and EndState. When the story is in LineState, it has produced zero or more lines of text since the last state it was in, and could produce zero or more lines before transitioning to ChoiceState or EndState. In EndState, the state is functionally inert, until it's brought back to LineState by setting the path. In ChoiceState, it has produced zero or more choices since the last LineState, and could produce zero or more choices before transitioning to ReadyState; I don't think it can go directly to EndState, but implementing that if I need it shouldn't be a problem. Actually, what should it do if it tries to transition without producing a Choice...? In ReadyState, it has (hopefully!) produced at least one Choice, and, given one of those choices, it will transition to either LineState or EndState; the latter transition might not be necessary, depending on how diverts to END are coded.
For serialization purposes, I don't think it poses any problems to deserialize no choices as a LineState, and some choices as a ChoiceState. The "real" state might be EndState or ReadyState, but it'll immediately enter them if needed. I could be wrong. We'll see.
Anyway, the conclusion I draw here is that all the states need most of these values, except for _currentChoices. So, I should probably define a helper that tracks all of that state and use that in the State classes, since I expect most data to need to persist through transitions.
Anyway, that's a good thing to work on the next few days. For now, I should get to bed.