521 lines
21 KiB
C
521 lines
21 KiB
C
|
|
// Copyright Steve Streeting 2022
|
|||
|
|
// Released under the MIT license https://opensource.org/license/MIT/
|
|||
|
|
#pragma once
|
|||
|
|
|
|||
|
|
#include "CoreMinimal.h"
|
|||
|
|
#include "SUDSExpression.h"
|
|||
|
|
|
|||
|
|
struct FSUDSMessageLogger;
|
|||
|
|
class USUDSScript;
|
|||
|
|
DECLARE_LOG_CATEGORY_EXTERN(LogSUDSImporter, Verbose, All);
|
|||
|
|
|
|||
|
|
struct SUDSEDITOR_API FSUDSParsedEdge
|
|||
|
|
{
|
|||
|
|
public:
|
|||
|
|
/// Text associated with this edge (if a player choice option)
|
|||
|
|
FString Text;
|
|||
|
|
/// Identifier of the text, for the string table
|
|||
|
|
FString TextID;
|
|||
|
|
/// Metadata associated with text, for translator comments
|
|||
|
|
TMap<FName, FString> TextMetadata;
|
|||
|
|
/// The line this edge was created on
|
|||
|
|
int SourceLineNo;
|
|||
|
|
/// Condition expression that applies to this edge (for select nodes)
|
|||
|
|
FSUDSExpression ConditionExpression;
|
|||
|
|
/// Custom metadata for a node which the user can set. Can be used to annotate choice lines
|
|||
|
|
/// Could be used to disable a choice if you don't have the stats to take it, or anything else
|
|||
|
|
/// where you need a bit of extra information about a line that doesn't suit setting a dialogue variable for.
|
|||
|
|
TMap<FName, FSUDSExpression> UserMetadata;
|
|||
|
|
|
|||
|
|
int SourceNodeIdx = -1;
|
|||
|
|
int TargetNodeIdx = -1;
|
|||
|
|
|
|||
|
|
FSUDSParsedEdge(int LineNo) : SourceLineNo(LineNo){}
|
|||
|
|
|
|||
|
|
FSUDSParsedEdge(int FromNodeIdx, int ToNodeIdx, int LineNo, const FString& InText, const FString& InTextID, const TMap<FName, FString>& Metadata, const TMap<FName, FSUDSExpression>& UserMeta)
|
|||
|
|
: Text(InText),
|
|||
|
|
TextID(InTextID),
|
|||
|
|
TextMetadata(Metadata),
|
|||
|
|
SourceLineNo(LineNo),
|
|||
|
|
UserMetadata(UserMeta),
|
|||
|
|
SourceNodeIdx(FromNodeIdx),
|
|||
|
|
TargetNodeIdx(ToNodeIdx)
|
|||
|
|
{
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
FSUDSParsedEdge(int FromNodeIdx, int ToNodeIdx, int LineNo)
|
|||
|
|
: SourceLineNo(LineNo),
|
|||
|
|
SourceNodeIdx(FromNodeIdx),
|
|||
|
|
TargetNodeIdx(ToNodeIdx)
|
|||
|
|
|
|||
|
|
{
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void Reset()
|
|||
|
|
{
|
|||
|
|
*this = FSUDSParsedEdge(-1);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
enum class ESUDSParsedNodeType : uint8
|
|||
|
|
{
|
|||
|
|
/// Text node, displaying a line of dialogue
|
|||
|
|
Text,
|
|||
|
|
/// Choice node, displaying a series of user choices which navigate to other nodes
|
|||
|
|
Choice,
|
|||
|
|
/// Select node, automatically selecting one which navigates to another node based on state (also Random)
|
|||
|
|
Select,
|
|||
|
|
/// Goto node, redirects execution somewhere else
|
|||
|
|
/// Gotos are only nodes in the parsing structure, because they need to be discoverable as a fallthrough destination
|
|||
|
|
/// When converting to runtime use they just become edges
|
|||
|
|
Goto,
|
|||
|
|
/// Gosub node, acts like goto except stores return location
|
|||
|
|
Gosub,
|
|||
|
|
/// Return node, returns from a gosub
|
|||
|
|
Return,
|
|||
|
|
/// Set variable node
|
|||
|
|
SetVariable,
|
|||
|
|
/// Event node
|
|||
|
|
Event
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
/// Intermediate parsed node from script text
|
|||
|
|
/// This will be converted into a final asset later
|
|||
|
|
struct SUDSEDITOR_API FSUDSParsedNode
|
|||
|
|
{
|
|||
|
|
public:
|
|||
|
|
ESUDSParsedNodeType NodeType;
|
|||
|
|
int OriginalIndent;
|
|||
|
|
/// Identifier is speaker ID, goto label, variable name etc
|
|||
|
|
FString Identifier;
|
|||
|
|
/// Text in native language
|
|||
|
|
FString Text;
|
|||
|
|
/// Identifier of the text, for the string table
|
|||
|
|
FString TextID;
|
|||
|
|
/// Metadata associated with text, for translator comments
|
|||
|
|
TMap<FName, FString> TextMetadata;
|
|||
|
|
/// Expression, for nodes that use it (e.g. set)
|
|||
|
|
FSUDSExpression Expression;
|
|||
|
|
/// Event arguments, for event nodes
|
|||
|
|
TArray<FSUDSExpression> EventArgs;
|
|||
|
|
/// Labels which lead to this node
|
|||
|
|
TArray<FString> Labels;
|
|||
|
|
/// Edges leading to other nodes
|
|||
|
|
TArray<FSUDSParsedEdge> Edges;
|
|||
|
|
/// The line this node was created on
|
|||
|
|
int SourceLineNo;
|
|||
|
|
/// Whether this is a valid fall-through target
|
|||
|
|
bool AllowFallthrough = true;
|
|||
|
|
|
|||
|
|
/// Custom metadata for a node which the user can set. Can be used to annotate speaker lines
|
|||
|
|
TMap<FName, FSUDSExpression> UserMetadata;
|
|||
|
|
|
|||
|
|
// Path hierarchy of choice nodes leading to this node, of the form "/C002/C006" etc, not including this node index
|
|||
|
|
// This helps us identify valid fallthroughs
|
|||
|
|
FString ChoicePath;
|
|||
|
|
// Path hierarchy of select nodes leading to this node, of the form "/S002/S006" etc, not including this node index
|
|||
|
|
// This helps us identify valid fallthroughs
|
|||
|
|
FString ConditionalPath;
|
|||
|
|
|
|||
|
|
/// Although multiple edges can lead here, this index is for the auto-connected parent (may be nothing)
|
|||
|
|
int ParentNodeIdx = -1;
|
|||
|
|
|
|||
|
|
FSUDSParsedNode(ESUDSParsedNodeType InNodeType, int Indent, int LineNo) : NodeType(InNodeType),
|
|||
|
|
OriginalIndent(Indent),
|
|||
|
|
SourceLineNo(LineNo)
|
|||
|
|
{
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
FSUDSParsedNode(const FString& Label,
|
|||
|
|
const FString& GosubID,
|
|||
|
|
int Indent,
|
|||
|
|
int LineNo) : NodeType(ESUDSParsedNodeType::Gosub),
|
|||
|
|
OriginalIndent(Indent),
|
|||
|
|
Identifier(Label),
|
|||
|
|
TextID(GosubID),
|
|||
|
|
SourceLineNo(LineNo)
|
|||
|
|
{
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
FSUDSParsedNode(const FString& InSpeaker, const FString& InText, const FString& InTextID, const TMap<FName, FString>& Metadata, const TMap<FName, FSUDSExpression>& UserMeta, int Indent, int LineNo)
|
|||
|
|
: NodeType(ESUDSParsedNodeType::Text),
|
|||
|
|
OriginalIndent(Indent),
|
|||
|
|
Identifier(InSpeaker),
|
|||
|
|
Text(InText),
|
|||
|
|
TextID(InTextID),
|
|||
|
|
TextMetadata(Metadata),
|
|||
|
|
SourceLineNo(LineNo),
|
|||
|
|
UserMetadata(UserMeta)
|
|||
|
|
{
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
FSUDSParsedNode(const FString& GotoLabel, int Indent, int LineNo)
|
|||
|
|
: NodeType(ESUDSParsedNodeType::Goto), OriginalIndent(Indent), Identifier(GotoLabel), SourceLineNo(LineNo)
|
|||
|
|
{
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
FSUDSParsedNode(const FString& VariableName, const FSUDSExpression& InExpr, int Indent, int LineNo)
|
|||
|
|
: NodeType(ESUDSParsedNodeType::SetVariable),
|
|||
|
|
OriginalIndent(Indent),
|
|||
|
|
Identifier(VariableName),
|
|||
|
|
Expression(InExpr),
|
|||
|
|
SourceLineNo(LineNo)
|
|||
|
|
{
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
FSUDSParsedNode(const FString& VariableName,
|
|||
|
|
const FSUDSExpression& InExpr,
|
|||
|
|
const FString& InTextID,
|
|||
|
|
int Indent,
|
|||
|
|
int LineNo)
|
|||
|
|
: NodeType(ESUDSParsedNodeType::SetVariable),
|
|||
|
|
OriginalIndent(Indent),
|
|||
|
|
Identifier(VariableName),
|
|||
|
|
TextID(InTextID),
|
|||
|
|
Expression(InExpr),
|
|||
|
|
SourceLineNo(LineNo)
|
|||
|
|
{
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
class SUDSEDITOR_API FSUDSScriptImporter
|
|||
|
|
{
|
|||
|
|
public:
|
|||
|
|
bool ImportFromBuffer(const TCHAR* Buffer, int32 Len, const FString& NameForErrors, FSUDSMessageLogger* Logger, bool bSilent);
|
|||
|
|
void PopulateAsset(USUDSScript* Asset, UStringTable* StringTable);
|
|||
|
|
static FMD5Hash CalculateHash(const TCHAR* Buffer, int32 Len);
|
|||
|
|
static const FString EndGotoLabel;
|
|||
|
|
protected:
|
|||
|
|
static const FString TreePathSeparator;
|
|||
|
|
|
|||
|
|
enum class EConditionalStage : uint8
|
|||
|
|
{
|
|||
|
|
IfStage,
|
|||
|
|
ElseIfStage,
|
|||
|
|
ElseStage,
|
|||
|
|
RandomStage,
|
|||
|
|
RandomOptionStage
|
|||
|
|
};
|
|||
|
|
enum class EConditionalParent : uint8
|
|||
|
|
{
|
|||
|
|
Select,
|
|||
|
|
ElseIfStage,
|
|||
|
|
ElseStage
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// Struct for tracking if/elseif blocks
|
|||
|
|
struct ConditionalContext
|
|||
|
|
{
|
|||
|
|
/// Index of parent select node where else will be added
|
|||
|
|
int SelectNodeIdx = -1;
|
|||
|
|
/// Previous block index (parent for nesting)
|
|||
|
|
int PreviousBlockIdx = -1;
|
|||
|
|
/// Track whether we're in if/elseif/else
|
|||
|
|
EConditionalStage Stage;
|
|||
|
|
/// String identifying the current condition; for elseif or else contains original "if" context
|
|||
|
|
FString ConditionPathElement;
|
|||
|
|
|
|||
|
|
ConditionalContext(int InSelectNodeIdx, int InPrevBlockIdx, EConditionalStage InStage, const FString& InCondStr) :
|
|||
|
|
SelectNodeIdx(InSelectNodeIdx),
|
|||
|
|
PreviousBlockIdx(InPrevBlockIdx),
|
|||
|
|
Stage(InStage),
|
|||
|
|
ConditionPathElement(InCondStr)
|
|||
|
|
{
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
/// Struct for tracking indents
|
|||
|
|
struct IndentContext
|
|||
|
|
{
|
|||
|
|
public:
|
|||
|
|
// The index of the Node which is the parent of this context
|
|||
|
|
// This potentially changes every time a sequential text node is encountered in the same context, so it's
|
|||
|
|
// always pointing to the last node encountered at this level, for connection
|
|||
|
|
int LastNodeIdx = -1;
|
|||
|
|
|
|||
|
|
/// The outermost indent level where this context lives
|
|||
|
|
/// You can indent things that don't create a new context, e.g.
|
|||
|
|
/// 1. Indent a text line under another text line: this is the same as no indent, just a continuation
|
|||
|
|
/// 2. Indent choices or conditions under a text line
|
|||
|
|
/// This is just good for readability, but does not create a new context, it's just a linear sequence
|
|||
|
|
/// Therefore the ThresholdIndent tracks the outermost indent relating to the current linear sequence, to know
|
|||
|
|
/// when you do in fact need to pop the current context off the stack.
|
|||
|
|
int ThresholdIndent = 0;
|
|||
|
|
|
|||
|
|
int LastTextNodeIdx = -1;
|
|||
|
|
|
|||
|
|
/// The path entry for this indent, to be combined with all previous levels to provide full path context
|
|||
|
|
FString PathEntry;
|
|||
|
|
|
|||
|
|
IndentContext(int NodeIdx, int Indent, const FString& Path) : LastNodeIdx(NodeIdx), ThresholdIndent(Indent), LastTextNodeIdx(-1), PathEntry(Path) {}
|
|||
|
|
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
/// A tree of nodes. Contained to separate header nodes from body nodes
|
|||
|
|
struct ParsedTree
|
|||
|
|
{
|
|||
|
|
public:
|
|||
|
|
/// The indent context stack representing where we are in the indentation tree while parsing
|
|||
|
|
/// There must always be 1 level (root)
|
|||
|
|
TArray<IndentContext> IndentLevelStack;
|
|||
|
|
/// When encountering conditions and choice lines, we are building up details for an edge to another node, but
|
|||
|
|
/// we currently don't know the target node. We keep these pending details here
|
|||
|
|
int EdgeInProgressNodeIdx = -1;
|
|||
|
|
int EdgeInProgressEdgeIdx = -1;
|
|||
|
|
/// List of all nodes, appended to as parsing progresses
|
|||
|
|
/// Ordering is important, these nodes must be in the order encountered in the file
|
|||
|
|
TArray<FSUDSParsedNode> Nodes;
|
|||
|
|
/// Record of goto labels to node index, built up during parsing (forward refs are OK so not complete until end of parsing)
|
|||
|
|
TMap<FString, int> GotoLabelList;
|
|||
|
|
/// Goto labels which have been encountered but we haven't found a destination yet
|
|||
|
|
TArray<FString> PendingGotoLabels;
|
|||
|
|
/// Goto labels that lead directly to another goto and thus are just aliases
|
|||
|
|
TMap<FString, FString> AliasedGotoLabels;
|
|||
|
|
|
|||
|
|
/// Conditional blocks
|
|||
|
|
/// "if" creates a new context, uses current as parent
|
|||
|
|
/// "elseif" and "else" also create new contexts, but copies parent from current (sibling)
|
|||
|
|
/// "endif" ends the context
|
|||
|
|
/// You cannot have conditionals that were started in an indent context ending outside it
|
|||
|
|
TArray<ConditionalContext> ConditionalBlocks;
|
|||
|
|
/// Index of the current conditional block, if any
|
|||
|
|
int CurrentConditionalBlockIdx = -1;
|
|||
|
|
|
|||
|
|
void Reset()
|
|||
|
|
{
|
|||
|
|
IndentLevelStack.Reset();
|
|||
|
|
EdgeInProgressNodeIdx = EdgeInProgressEdgeIdx -1;
|
|||
|
|
Nodes.Reset();
|
|||
|
|
GotoLabelList.Reset();
|
|||
|
|
PendingGotoLabels.Reset();
|
|||
|
|
AliasedGotoLabels.Reset();
|
|||
|
|
ConditionalBlocks.Reset();
|
|||
|
|
CurrentConditionalBlockIdx = -1;
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
ParsedTree HeaderTree;
|
|||
|
|
ParsedTree BodyTree;
|
|||
|
|
|
|||
|
|
struct ParsedMetadata
|
|||
|
|
{
|
|||
|
|
public:
|
|||
|
|
FName Key;
|
|||
|
|
FString Value;
|
|||
|
|
int IndentLevel;
|
|||
|
|
|
|||
|
|
ParsedMetadata(const FName& InKey, const FString& InValue, int InIndentLevel)
|
|||
|
|
: Key(InKey),
|
|||
|
|
Value(InValue),
|
|||
|
|
IndentLevel(InIndentLevel)
|
|||
|
|
{
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
/// Text Metadata applied to speaker lines / choices until reset
|
|||
|
|
/// For each key there's a stack of metadata, with most indented at the top
|
|||
|
|
TMap<FName, TArray<ParsedMetadata>> PersistentMetadata;
|
|||
|
|
/// Text Metadata applied just to the next speaker line or choice
|
|||
|
|
TMap<FName, ParsedMetadata> TransientMetadata;
|
|||
|
|
/// User metadata for the next speaker line or choice
|
|||
|
|
TMap<FName, FSUDSExpression> UserMetadata;
|
|||
|
|
|
|||
|
|
/// List of speakers, detected during parsing of lines of text
|
|||
|
|
TArray<FString> ReferencedSpeakers;
|
|||
|
|
|
|||
|
|
const int TabIndentValue = 4;
|
|||
|
|
bool bHeaderDone = false;
|
|||
|
|
bool bTooLateForHeader = false;
|
|||
|
|
bool bHeaderInProgress = false;
|
|||
|
|
TOptional<bool> bOverrideGenerateSpeakerLineForChoice;
|
|||
|
|
TOptional<FString> OverrideChoiceSpeakerID;
|
|||
|
|
bool bTextInProgress = false;
|
|||
|
|
int ChoiceUniqueId = 0;
|
|||
|
|
/// For generating text IDs
|
|||
|
|
int TextIDHighestNumber = 0;
|
|||
|
|
/// For generating gosub IDs
|
|||
|
|
int GosubIDHighestNumber = 0;
|
|||
|
|
/// Parse a single line
|
|||
|
|
bool ParseLine(const FStringView& Line, int LineNo, const FString& NameForErrors, FSUDSMessageLogger* Logger, bool bSilent);
|
|||
|
|
bool ParseHeaderLine(const FStringView& Line, int IndentLevel, int LineNo, const FString& NameForErrors, FSUDSMessageLogger* Logger, bool bSilent);
|
|||
|
|
bool ParseBodyLine(const FStringView& Line, int IndentLevel, int LineNo, const FString& NameForErrors, FSUDSMessageLogger* Logger, bool bSilent);
|
|||
|
|
bool ParseCommentMetadataLine(const FStringView& Line, int IndentLevel, int LineNo, const FString& NameForErrors, FSUDSMessageLogger* Logger, bool bSilent);
|
|||
|
|
bool IsLastNodeOfType(const ParsedTree& Tree, ESUDSParsedNodeType Type);
|
|||
|
|
bool ParseChoiceLine(const FStringView& Line, ParsedTree& Tree, int IndentLevel, int LineNo, const FString& NameForErrors, FSUDSMessageLogger*
|
|||
|
|
Logger,
|
|||
|
|
bool bSilent);
|
|||
|
|
FSUDSParsedEdge* GetEdgeInProgress(ParsedTree& Tree);
|
|||
|
|
void EnsureChoiceNodeExistsAboveSelect(ParsedTree& Tree, int IndentLevel, int LineNo);
|
|||
|
|
static bool IsConditionalLine(const FStringView& Line);
|
|||
|
|
bool ParseConditionalLine(const FStringView& Line, ParsedTree& Tree, int IndentLevel, int LineNo, const FString& NameForErrors, FSUDSMessageLogger* Logger, bool bSilent);
|
|||
|
|
bool ParseIfLine(const FStringView& Line,
|
|||
|
|
ParsedTree& Tree,
|
|||
|
|
const FString& ConditionStr,
|
|||
|
|
int IndentLevel,
|
|||
|
|
int LineNo,
|
|||
|
|
const FString& NameForErrors,
|
|||
|
|
FSUDSMessageLogger* Logger,
|
|||
|
|
bool bSilent);
|
|||
|
|
bool ParseElseIfLine(const FStringView& Line,
|
|||
|
|
ParsedTree& Tree,
|
|||
|
|
const FString& ConditionStr,
|
|||
|
|
int IndentLevel,
|
|||
|
|
int LineNo,
|
|||
|
|
const FString& NameForErrors,
|
|||
|
|
FSUDSMessageLogger* Logger,
|
|||
|
|
bool bSilent);
|
|||
|
|
|
|||
|
|
bool ParseElseLine(const FStringView& Line,
|
|||
|
|
ParsedTree& Tree,
|
|||
|
|
int IndentLevel,
|
|||
|
|
int LineNo,
|
|||
|
|
const FString& NameForErrors,
|
|||
|
|
FSUDSMessageLogger* Logger,
|
|||
|
|
bool bSilent);
|
|||
|
|
bool ParseEndIfLine(const FStringView& Line,
|
|||
|
|
ParsedTree& Tree,
|
|||
|
|
int IndentLevel,
|
|||
|
|
int LineNo,
|
|||
|
|
const FString& NameForErrors,
|
|||
|
|
FSUDSMessageLogger*
|
|||
|
|
Logger,
|
|||
|
|
bool bSilent);
|
|||
|
|
static bool IsRandomLine(const FStringView& Line);
|
|||
|
|
bool ParseRandomLine(const FStringView& Line,
|
|||
|
|
ParsedTree& Tree,
|
|||
|
|
int IndentLevel,
|
|||
|
|
int LineNo,
|
|||
|
|
const FString& NameForErrors,
|
|||
|
|
FSUDSMessageLogger* Logger,
|
|||
|
|
bool bSilent);
|
|||
|
|
bool ParseBeginRandomLine(const FStringView& Line,
|
|||
|
|
ParsedTree& Tree,
|
|||
|
|
int IndentLevel,
|
|||
|
|
int LineNo,
|
|||
|
|
const FString& NameForErrors,
|
|||
|
|
FSUDSMessageLogger* Logger,
|
|||
|
|
bool bSilent);
|
|||
|
|
bool ParseRandomOptionLine(const FStringView& Line,
|
|||
|
|
ParsedTree& Tree,
|
|||
|
|
int IndentLevel,
|
|||
|
|
int LineNo,
|
|||
|
|
const FString& NameForErrors,
|
|||
|
|
FSUDSMessageLogger* Logger,
|
|||
|
|
bool bSilent);
|
|||
|
|
bool ParseEndRandomLine(const FStringView& Line,
|
|||
|
|
ParsedTree& Tree,
|
|||
|
|
int IndentLevel,
|
|||
|
|
int LineNo,
|
|||
|
|
const FString& NameForErrors,
|
|||
|
|
FSUDSMessageLogger* Logger,
|
|||
|
|
bool bSilent);
|
|||
|
|
bool ParseGotoLabelLine(const FStringView& Line,
|
|||
|
|
ParsedTree& Tree,
|
|||
|
|
int IndentLevel,
|
|||
|
|
int LineNo,
|
|||
|
|
const FString& NameForErrors,
|
|||
|
|
FSUDSMessageLogger* Logger,
|
|||
|
|
bool bSilent);
|
|||
|
|
bool ParseGotoLine(const FStringView& Line,
|
|||
|
|
ParsedTree& Tree,
|
|||
|
|
int IndentLevel,
|
|||
|
|
int LineNo,
|
|||
|
|
const FString& NameForErrors,
|
|||
|
|
FSUDSMessageLogger* Logger,
|
|||
|
|
bool bSilent);
|
|||
|
|
bool ParseGosubLine(const FStringView& Line,
|
|||
|
|
ParsedTree& Tree,
|
|||
|
|
int IndentLevel,
|
|||
|
|
int LineNo,
|
|||
|
|
const FString& NameForErrors,
|
|||
|
|
FSUDSMessageLogger* Logger,
|
|||
|
|
bool bSilent);
|
|||
|
|
bool ParseReturnLine(const FStringView& Line,
|
|||
|
|
ParsedTree& Tree,
|
|||
|
|
int IndentLevel,
|
|||
|
|
int LineNo,
|
|||
|
|
const FString& NameForErrors,
|
|||
|
|
FSUDSMessageLogger* Logger,
|
|||
|
|
bool bSilent);
|
|||
|
|
bool ParseSetLine(const FStringView& Line,
|
|||
|
|
ParsedTree& Tree,
|
|||
|
|
int IndentLevel,
|
|||
|
|
int LineNo,
|
|||
|
|
const FString& NameForErrors,
|
|||
|
|
FSUDSMessageLogger* Logger,
|
|||
|
|
bool bSilent);
|
|||
|
|
bool ParseEventLine(const FStringView& Line,
|
|||
|
|
ParsedTree& Tree,
|
|||
|
|
int IndentLevel,
|
|||
|
|
int LineNo,
|
|||
|
|
const FString& NameForErrors,
|
|||
|
|
FSUDSMessageLogger* Logger,
|
|||
|
|
bool bSilent);
|
|||
|
|
bool ParseTextLine(const FStringView& Line,
|
|||
|
|
ParsedTree& Tree,
|
|||
|
|
int IndentLevel,
|
|||
|
|
int LineNo,
|
|||
|
|
const FString& NameForErrors,
|
|||
|
|
FSUDSMessageLogger* Logger,
|
|||
|
|
bool bSilent);
|
|||
|
|
bool ParseImportSettingLine(const FStringView& Line,
|
|||
|
|
ParsedTree& Tree,
|
|||
|
|
int IndentLevel,
|
|||
|
|
int LineNo,
|
|||
|
|
const FString& NameForErrors,
|
|||
|
|
FSUDSMessageLogger* Logger,
|
|||
|
|
bool bSilent);
|
|||
|
|
TMap<FName, FString> GetTextMetadataForNextEntry(int CurrentLineIndent);
|
|||
|
|
TMap<FName, FSUDSExpression> ConsumeUserMetadata();
|
|||
|
|
bool IsCommentLine(const FStringView& TrimmedLine);
|
|||
|
|
FStringView TrimLine(const FStringView& Line, int& OutIndentLevel) const;
|
|||
|
|
int FindChoiceAfterTextNode(const FSUDSScriptImporter::ParsedTree& Tree, int TextNodeIdx, const FString& ConditionalPath);
|
|||
|
|
int RecurseChoiceNodeFindDeepest(const ParsedTree& Tree, int FromChoiceIdx, const FString& ConditionalPath);
|
|||
|
|
int RecurseSelectNodeFindDeepestChoice(const ParsedTree& Tree, int FromSelectNode, const FString& ConditionalPath);
|
|||
|
|
int FindEdge(const FSUDSScriptImporter::ParsedTree& Tree, int ParentNodeIdx, int TargetNodeIndex);
|
|||
|
|
FString MakeIfConditionPathElement(int SelectNodeIdx, const FString& ConditionStr);
|
|||
|
|
FString MakeElseIfConditionPathElement(int SelectNodeIdx, const FString& ConditionStr);
|
|||
|
|
FString MakeElseConditionPathElement(int SelectNodeIdx);
|
|||
|
|
int FindLastChoiceNode(const ParsedTree& Tree, int IndentLevel);
|
|||
|
|
int FindLastChoiceNode(const ParsedTree& Tree, int IndentLevel, int FromIndex, const FString& ConditionPath);
|
|||
|
|
void PopIndent(ParsedTree& Tree);
|
|||
|
|
void PushIndent(ParsedTree& Tree, int NodeIdx, int Indent, const FString& Path);
|
|||
|
|
FString GetCurrentTreePath(const FSUDSScriptImporter::ParsedTree& Tree);
|
|||
|
|
FString GetCurrentTreeConditionalPath(const FSUDSScriptImporter::ParsedTree& Tree);
|
|||
|
|
FString GetTreeConditionalPath(const ParsedTree& Tree, int NodeIndex);
|
|||
|
|
void SetFallthroughForNewNode(FSUDSScriptImporter::ParsedTree& Tree, FSUDSParsedNode& NewNode);
|
|||
|
|
int AppendNode(ParsedTree& Tree, const FSUDSParsedNode& InNode);
|
|||
|
|
bool SelectNodeIsMissingElsePath(const FSUDSScriptImporter::ParsedTree& Tree, const FSUDSParsedNode& Node);
|
|||
|
|
bool PostImportSanityCheck(const FString& NameForErrors, FSUDSMessageLogger* Logger, bool bSilent);
|
|||
|
|
bool ChoiceNodeCheckPaths(const FSUDSParsedNode& ChoiceNode,
|
|||
|
|
const FString& NameForErrors,
|
|||
|
|
FSUDSMessageLogger* Logger,
|
|||
|
|
bool bSilent);
|
|||
|
|
bool RecurseChoiceNodeCheckPaths(const FSUDSParsedNode& OrigChoiceNode, const FSUDSParsedNode& CurrChoiceNode, const FString& NameForErrors, FSUDSMessageLogger* Logger, bool bSilent);
|
|||
|
|
bool RecurseChoiceNodeCheckPaths(const FSUDSParsedNode& ChoiceNode, const FSUDSParsedEdge& Edge, const FString& NameForErrors, FSUDSMessageLogger*
|
|||
|
|
Logger,
|
|||
|
|
bool bSilent);
|
|||
|
|
void ConnectRemainingNodes(ParsedTree& Tree, const FString& NameForErrors, FSUDSMessageLogger* Logger, bool bSilent);
|
|||
|
|
void GenerateTextIDs(ParsedTree& BodyTree);
|
|||
|
|
int FindFallthroughNodeIndex(ParsedTree& Tree, int StartNodeIndex, const FString& FromChoicePath, const FString& FromConditionalPath);
|
|||
|
|
bool RetrieveAndRemoveTextID(FStringView& InOutLine, FString& OutTextID);
|
|||
|
|
bool RetrieveAndRemoveGosubID(FStringView& InOutLine, FString& OutTextID);
|
|||
|
|
FString GenerateTextID();
|
|||
|
|
const FSUDSParsedNode* GetNode(const ParsedTree& Tree, int Index = 0);
|
|||
|
|
int GetGotoTargetNodeIndex(const ParsedTree& Tree, const FString& InLabel);
|
|||
|
|
void PopulateAssetFromTree(USUDSScript* Asset,
|
|||
|
|
const ParsedTree& Tree,
|
|||
|
|
TArray<TObjectPtr<class USUDSScriptNode>>* pOutNodes,
|
|||
|
|
TMap<FName, int>* pOutLabels,
|
|||
|
|
UStringTable* StringTable);
|
|||
|
|
|
|||
|
|
public:
|
|||
|
|
const FSUDSParsedNode* GetNode(int Index = 0);
|
|||
|
|
const FSUDSParsedNode* GetHeaderNode(int Index = 0);
|
|||
|
|
/// Resolve a goto label to a target index (after import), or -1 if not resolvable
|
|||
|
|
int GetGotoTargetNodeIndex(const FString& Label);
|
|||
|
|
static bool RetrieveTextIDFromLine(FStringView& InOutLine, FString& OutTextID, int& OutNumber);
|
|||
|
|
static bool RetrieveGosubIDFromLine(FStringView& InOutLine, FString& OutID, int& OutNumber);
|
|||
|
|
};
|