Documentation ¶
Overview ¶
Package yarn implements the Yarn Spinner virtual machine and dialogue system. For the original implementation, see https://yarnspinner.dev and https://github.com/YarnSpinnerTool/YarnSpinner.
Index ¶
- Constants
- func ConvertToBool(x interface{}) (bool, error)
- func ConvertToFloat32(x interface{}) (float32, error)
- func ConvertToFloat64(x interface{}) (float64, error)
- func ConvertToInt(x interface{}) (int, error)
- func ConvertToString(x interface{}) string
- func FormatInstruction(inst *yarnpb.Instruction) string
- func FormatProgram(w io.Writer, prog *yarnpb.Program) error
- func FormatProgramString(prog *yarnpb.Program) string
- func LoadProgramFile(programPath string) (*yarnpb.Program, error)
- type AsyncAdapter
- func (a *AsyncAdapter) Abort(err error) error
- func (a *AsyncAdapter) Command(command string) error
- func (a *AsyncAdapter) DialogueComplete() error
- func (a *AsyncAdapter) Go() error
- func (a *AsyncAdapter) GoWithChoice(id int) error
- func (a *AsyncAdapter) Line(line Line) error
- func (a *AsyncAdapter) NodeComplete(nodeName string) error
- func (a *AsyncAdapter) NodeStart(nodeName string) error
- func (a *AsyncAdapter) Options(options []Option) (int, error)
- func (a *AsyncAdapter) PrepareForLines(lineIDs []string) error
- func (a *AsyncAdapter) State() VMState
- type AsyncDialogueHandler
- type Attribute
- type AttributedString
- type DialogueHandler
- type FakeAsyncDialogueHandler
- func (f FakeAsyncDialogueHandler) Command(string)
- func (f FakeAsyncDialogueHandler) DialogueComplete()
- func (f FakeAsyncDialogueHandler) Line(Line)
- func (f FakeAsyncDialogueHandler) NodeComplete(string)
- func (f FakeAsyncDialogueHandler) NodeStart(string)
- func (f FakeAsyncDialogueHandler) Options(options []Option)
- func (f FakeAsyncDialogueHandler) PrepareForLines([]string)
- type FakeDialogueHandler
- func (FakeDialogueHandler) Command(string) error
- func (FakeDialogueHandler) DialogueComplete() error
- func (FakeDialogueHandler) Line(Line) error
- func (FakeDialogueHandler) NodeComplete(string) error
- func (FakeDialogueHandler) NodeStart(string) error
- func (FakeDialogueHandler) Options(options []Option) (int, error)
- func (FakeDialogueHandler) PrepareForLines([]string) error
- type FuncMap
- type Line
- type MapVariableStorage
- func (m *MapVariableStorage) Clear()
- func (m *MapVariableStorage) Clone() *MapVariableStorage
- func (m *MapVariableStorage) Contents() map[string]any
- func (m *MapVariableStorage) Delete(names ...string)
- func (m *MapVariableStorage) GetValue(name string) (value any, found bool)
- func (m *MapVariableStorage) ReplaceContents(src map[string]any)
- func (m *MapVariableStorage) SetValue(name string, value any)
- type Option
- type StringTable
- func LoadFiles(programPath, langCode string) (*yarnpb.Program, *StringTable, error)
- func LoadFilesFS(fsys fs.FS, programPath, langCode string) (*yarnpb.Program, *StringTable, error)
- func LoadStringTableFile(stringTablePath, langCode string) (*StringTable, error)
- func LoadStringTableFileFS(fsys fs.FS, stringTablePath, langCode string) (*StringTable, error)
- func ReadStringTable(r io.Reader, langCode string) (*StringTable, error)
- type StringTableRow
- type TestPlan
- type TestStep
- type VMState
- type VMStateMismatchErr
- type VariableStorage
- type VirtualMachine
Constants ¶
const ( // No event has been delivered (since the last call to Go / GoWithOption); // the VM is executing. VMStateRunning = iota // An event other than Options was delivered, and VM execution is blocked. VMStatePaused // Options event was delivered, and VM execution is blocked. VMStatePausedOptions // Execution has not begun, or has ended (e.g. by calling Abort, or any // other error). VMStateStopped )
const ( // ErrNilDialogueHandler indicates that Handler hasn't been set. ErrNilDialogueHandler = virtualMachineError("nil dialogue handler") // ErrNilVariableStorage indicates that Vars hasn't been set. ErrNilVariableStorage = virtualMachineError("nil variable storage") // ErrMissingProgram indicates that Program hasn't been set. ErrMissingProgram = virtualMachineError("missing or empty program") // ErrNoOptions indicates the program is invalid - it tried to show options // but none had been added. ErrNoOptions = virtualMachineError("no options were added") // ErrStackUnderflow indicates the program tried to pop or peek when the // stack was empty. ErrStackUnderflow = virtualMachineError("stack underflow") // ErrWrongType indicates the program needed a stack value, operand, or // function of one type, but got something else instead. ErrWrongType = virtualMachineError("wrong type") // ErrNotConvertible indicates the program tried to convert a stack value // or operand to a different type, but it was not convertible to that type. ErrNotConvertible = virtualMachineError("not convertible") // ErrNodeNotFound is returned where Run or SetNode is passed the name of a // node that is not in the program. ErrNodeNotFound = virtualMachineError("node not found") // ErrLabelNotFound indicates the program tries to jump to a label that // isn't in the label table for the current node. ErrLabelNotFound = virtualMachineError("label not found") // ErrNilOperand indicates the a malformed program containing an instruction // that requires a usable operand but the operand was nil. ErrNilOperand = virtualMachineError("nil operand") // ErrFunctionNotFound indicates the program tried to call a function but // that function is not in the FuncMap. ErrFunctionNotFound = virtualMachineError("function not found") // ErrFunctionArgMismatch indicates the program tried to call a function but // had the wrong number or types of args to pass to it. ErrFunctionArgMismatch = virtualMachineError("arg mismatch") )
Various sentinel errors returned by the virtual machine.
const ErrAlreadyStopped = virtualMachineError("VM already stopped or stopping")
ErrAlreadyStopped is returned when the AsyncAdapter cannot stop the virtual machine, because it is already stopped.
const Stop = virtualMachineError("stop")
Stop stops the virtual machine without error. It is used by the STOP instruction, but can also be returned by your handler to stop the VM in the same way. However a stop happens, NodeComplete and DialogueComplete are still called.
Variables ¶
This section is empty.
Functions ¶
func ConvertToBool ¶
ConvertToBool attempts conversion of the standard Yarn Spinner VM types (bool, number, string, null) to bool.
func ConvertToFloat32 ¶
ConvertToFloat32 attempts conversion of the standard Yarn Spinner VM types (bool, number, string, null) to a float32.
func ConvertToFloat64 ¶
ConvertToFloat64 attempts conversion of the standard Yarn Spinner VM types (bool, number, string, null) to a float64.
func ConvertToInt ¶
ConvertToInt attempts conversion of the standard Yarn Spinner VM types to (bool, number, string, null) to int.
func ConvertToString ¶
func ConvertToString(x interface{}) string
ConvertToString converts a value to a string, in a way that matches what Yarn Spinner does. nil becomes "null", and booleans are title-cased.
func FormatInstruction ¶
func FormatInstruction(inst *yarnpb.Instruction) string
FormatInstruction prints an instruction in a format convenient for debugging. The output is intended for human consumption only and may change between incremental versions of this package.
func FormatProgram ¶
FormatProgram prints a program in a format convenient for debugging to the io.Writer. The output is intended for human consumption only and may change between incremental versions of this package.
func FormatProgramString ¶
FormatProgramString prints the whole program into a string.
Types ¶
type AsyncAdapter ¶
type AsyncAdapter struct {
// contains filtered or unexported fields
}
AsyncAdapter is a DialogueHandler that exposes an interface that is similar to the mainline YarnSpinner VM dialogue handler. Instead of manually blocking inside the DialogueHandler callbacks, AsyncAdapter does this for you, until you call Go, GoWithChoice, or Abort (as appropriate).
func NewAsyncAdapter ¶
func NewAsyncAdapter(h AsyncDialogueHandler) *AsyncAdapter
NewAsyncAdapter returns a new AsyncAdapter.
func (*AsyncAdapter) Abort ¶
func (a *AsyncAdapter) Abort(err error) error
Abort stops the VM with the given error as soon as possible (either within the current event, or on the next event). If a nil error is passed, Abort will replace it with Stop (so that NodeComplete and DialogueComplete still fire). If the VM is already stopped (either through Abort, or after the DialogueComplete event) an error will be returned.
func (*AsyncAdapter) Command ¶
func (a *AsyncAdapter) Command(command string) error
Command is called by the VM and blocks until Go or Abort is called.
func (*AsyncAdapter) DialogueComplete ¶
func (a *AsyncAdapter) DialogueComplete() error
DialogueComplete is called by the VM and blocks until Go or Abort is called.
func (*AsyncAdapter) Go ¶
func (a *AsyncAdapter) Go() error
Go will continue the VM after it has delivered any event (other than Options). If the VM is not paused following any event other than Options, an error will be returned.
func (*AsyncAdapter) GoWithChoice ¶
func (a *AsyncAdapter) GoWithChoice(id int) error
GoWithChoice will continue the VM after it has delivered an Options event. Pass the ID of the chosen option. If the VM is not paused following an Options event, an error will be returned.
func (*AsyncAdapter) Line ¶
func (a *AsyncAdapter) Line(line Line) error
Line is called by the VM and blocks until Go or Abort is called.
func (*AsyncAdapter) NodeComplete ¶
func (a *AsyncAdapter) NodeComplete(nodeName string) error
NodeComplete is called by the VM and blocks until Go or Abort is called.
func (*AsyncAdapter) NodeStart ¶
func (a *AsyncAdapter) NodeStart(nodeName string) error
NodeStart is called by the VM and blocks until Go or Abort is called.
func (*AsyncAdapter) Options ¶
func (a *AsyncAdapter) Options(options []Option) (int, error)
Options is called by the VM and blocks until GoWithChoice or Abort is called.
func (*AsyncAdapter) PrepareForLines ¶
func (a *AsyncAdapter) PrepareForLines(lineIDs []string) error
PrepareForLines is called by the VM and blocks until Go or Abort is called.
func (*AsyncAdapter) State ¶
func (a *AsyncAdapter) State() VMState
State returns the current state.
type AsyncDialogueHandler ¶
type AsyncDialogueHandler interface { // NodeStart is called when a node has begun executing. It is passed the // name of the node. NodeStart(nodeName string) // PrepareForLines is called when the dialogue system anticipates that it // will deliver some lines. Note that not every line prepared may end up // being run. PrepareForLines(lineIDs []string) // Line is called when the dialogue system runs a line of dialogue. Line(line Line) // Options is called to deliver a set of options to the game. The player // should choose one of the options. Options(options []Option) // Command is called when the dialogue system runs a command. Command(command string) // NodeComplete is called when a node has completed execution. It is passed // the name of the node. NodeComplete(nodeName string) // DialogueComplete is called when the dialogue as a whole is complete. DialogueComplete() }
AsyncDialogueHandler receives events from AsyncAdapter. Unlike DialogueHandler, during each event the VM execution is paused automatically until Go, GoWithChoice, or Abort is called.
type Attribute ¶
Attribute describes a range within a string with additional information provided by markup tags. Start and End specify the range in bytes. Name is the tag name, and Props contains any additional key="value" tag properties.
type AttributedString ¶
type AttributedString struct {
// contains filtered or unexported fields
}
AttributedString is a string with additional attributes, such as presentation or styling information, that apply to the whole string or substrings.
func (*AttributedString) ScanAttribEvents ¶
func (s *AttributedString) ScanAttribEvents(visit func(pos int, atts []*Attribute))
ScanAttribEvents calls visit with each change in attribute state. pos is the byte position in the string where the change occurs. atts will contain the attributes that either start or end at pos, in the same order they were read from the original markup. Self-closing tags, or an open and close pair that apply to the same position (i.e. marking up nothing) will only be present in atts once (in the order of the start tag). For example, for the original string:
`[a]Hello A[/a] [b]Hello B[/b] [c][d][/c]No C, [e/]only D[/d]`
which is processed into the unattributed string:
`Hello A Hello B No C, only D`
ScanAttribEvents will visit: * (0, [a]) -- open of a * (7, [a]) -- close of a * (8, [b]) -- open of b * (15, [b]) -- close of b * (16, [c,d]) -- close of c applies to same position, so it appears once * (22, [e]) -- e is self-closing, so it appears once * (28, [d]) -- close of d
func (*AttributedString) String ¶
func (s *AttributedString) String() string
type DialogueHandler ¶
type DialogueHandler interface { // NodeStart is called when a node has begun executing. It is passed the // name of the node. NodeStart(nodeName string) error // PrepareForLines is called when the dialogue system anticipates that it // will deliver some lines. Note that not every line prepared may end up // being run. PrepareForLines(lineIDs []string) error // Line is called when the dialogue system runs a line of dialogue. Line(line Line) error // Options is called to deliver a set of options to the game. The player // should choose one of the options, and Options should return the ID of the // chosen option. Options(options []Option) (int, error) // Command is called when the dialogue system runs a command. Command(command string) error // NodeComplete is called when a node has completed execution. It is passed // the name of the node. NodeComplete(nodeName string) error // DialogueComplete is called when the dialogue as a whole is complete. DialogueComplete() error }
DialogueHandler receives events from the virtual machine.
type FakeAsyncDialogueHandler ¶
type FakeAsyncDialogueHandler struct {
AsyncAdapter *AsyncAdapter
}
FakeAsyncDialogueHandler implements AsyncDialogueHandler with minimal methods that immediately continue the VM. This is useful both for testing, and for satisfying the AsyncDialogueHandler interface via embedding, e.g.:
type MyHandler struct { FakeAsyncDialogueHandler } // MyHandler is only interested in Line and Options. func (m MyHandler) Line(line Line) { ... } func (m MyHandler) Options(options []Option) { ... } // All the other AsyncDialogueHandler methods provided by // FakeAsyncDialogueHandler.
Note that FakeAsyncDialogueHandler needs a reference to the AsyncAdapter (in order to call Go or GoWithChoice).
func (FakeAsyncDialogueHandler) Command ¶
func (f FakeAsyncDialogueHandler) Command(string)
Command calls AsyncAdapter.Go.
func (FakeAsyncDialogueHandler) DialogueComplete ¶
func (f FakeAsyncDialogueHandler) DialogueComplete()
DialogueComplete calls AsyncAdapter.Go.
func (FakeAsyncDialogueHandler) Line ¶
func (f FakeAsyncDialogueHandler) Line(Line)
Line calls AsyncAdapter.Go.
func (FakeAsyncDialogueHandler) NodeComplete ¶
func (f FakeAsyncDialogueHandler) NodeComplete(string)
NodeComplete calls AsyncAdapter.Go.
func (FakeAsyncDialogueHandler) NodeStart ¶
func (f FakeAsyncDialogueHandler) NodeStart(string)
NodeStart calls AsyncAdapter.Go.
func (FakeAsyncDialogueHandler) Options ¶
func (f FakeAsyncDialogueHandler) Options(options []Option)
Options calls AsyncAdapter.GoWithChoice with the ID of the first option, or AsyncAdapter.Abort if there are no options.
func (FakeAsyncDialogueHandler) PrepareForLines ¶
func (f FakeAsyncDialogueHandler) PrepareForLines([]string)
PrepareForLines calls AsyncAdapter.Go.
type FakeDialogueHandler ¶
type FakeDialogueHandler struct{}
FakeDialogueHandler implements DialogueHandler with minimal, do-nothing methods. This is useful both for testing, and for satisfying the DialogueHandler via embedding, e.g.:
type MyHandler struct { FakeDialogueHandler } // MyHandler is only interested in Line and Options. func (m MyHandler) Line(line Line) error { ... } func (m MyHandler) Options(options []Option) (int, error) { ... } // All the other DialogueHandler methods provided by FakeDialogueHandler.
func (FakeDialogueHandler) Command ¶
func (FakeDialogueHandler) Command(string) error
Command returns nil.
func (FakeDialogueHandler) DialogueComplete ¶
func (FakeDialogueHandler) DialogueComplete() error
DialogueComplete returns nil.
func (FakeDialogueHandler) NodeComplete ¶
func (FakeDialogueHandler) NodeComplete(string) error
NodeComplete returns nil.
func (FakeDialogueHandler) NodeStart ¶
func (FakeDialogueHandler) NodeStart(string) error
NodeStart returns nil.
func (FakeDialogueHandler) Options ¶
func (FakeDialogueHandler) Options(options []Option) (int, error)
Options returns the first option ID, or an error if there are no options.
func (FakeDialogueHandler) PrepareForLines ¶
func (FakeDialogueHandler) PrepareForLines([]string) error
PrepareForLines returns nil.
type FuncMap ¶
type FuncMap map[string]interface{}
FuncMap maps function names to implementations. It is similar to the text/template FuncMap.
Each function must return either 0, 1, or 2 values, and if 2 are returned, the latter must be type `error`.
If the arguments being passed by the program are not assignable to an argument, and the argument has type bool, int, float32, float64, or string, then a conversion is attempted by the VM. For example, if the stack has the values ("3", true, 2) on top, CALL_FUNC with "Number.Add" (see below) would cause Number.Add's implementation to be called with (3.0, 1.0) (the 2 is the argument count).
type Line ¶
type Line struct { // The string ID for the line. ID string // Values that should be interpolated into the user-facing text. Substitutions []string }
Line represents a line of dialogue.
type MapVariableStorage ¶
type MapVariableStorage struct {
// contains filtered or unexported fields
}
MapVariableStorage implements VariableStorage, in memory, using a map. In addition to the core VariableStorage functionality, there are methods for accessing the contents as an ordinary map[string]any.
func NewMapVariableStorage ¶
func NewMapVariableStorage() *MapVariableStorage
NewMapVariableStorage creates a new empty MapVariableStorage.
func NewMapVariableStorageFromMap ¶
func NewMapVariableStorageFromMap(src map[string]any) *MapVariableStorage
NewMapVariableStorageFromMap creates a new MapVariableStorage with initial contents copied from src. It does not keep a reference to src.
func (*MapVariableStorage) Clear ¶
func (m *MapVariableStorage) Clear()
Clear empties the storage of all values.
func (*MapVariableStorage) Clone ¶
func (m *MapVariableStorage) Clone() *MapVariableStorage
Clone returns a new MapVariableStorage that is a clone of the receiver. The new storage is a deep copy, and does not contain a reference to the original map inside the receiver (to avoid accidental data races).
func (*MapVariableStorage) Contents ¶
func (m *MapVariableStorage) Contents() map[string]any
Contents returns a copy of the contents of the storage, as a regular map. The returned map is a copy, it is not a reference to the map contained within the storage (to avoid accidental data races).
func (*MapVariableStorage) Delete ¶
func (m *MapVariableStorage) Delete(names ...string)
Delete deletes values from the storage.
func (*MapVariableStorage) GetValue ¶
func (m *MapVariableStorage) GetValue(name string) (value any, found bool)
GetValue fetches a value from the storage, returning (nil, false) if not present.
func (*MapVariableStorage) ReplaceContents ¶
func (m *MapVariableStorage) ReplaceContents(src map[string]any)
ReplaceContents replaces the contents of the storage with values from a regular map. ReplaceContents copies src, it does not keep a reference to src (to avoid accidental data races).
func (*MapVariableStorage) SetValue ¶
func (m *MapVariableStorage) SetValue(name string, value any)
SetValue sets a value in the storage.
type Option ¶
type Option struct { // A number identifying this option. If this option is selected, pass // this number back to the dialogue system. ID int // The line that should be presented for this option. Line Line // Name of the node that will run next, if this option is selected. DestinationNode string // Indicates whether the player should be permitted to select the option. // This is false for options that the player _could_ have taken if they had // satisfied some prerequisite earlier in the game. IsAvailable bool }
Option represents one option (among others) that the player could choose.
type StringTable ¶
type StringTable struct { Language language.Tag Table map[string]*StringTableRow }
StringTable contains all the information from a string table, keyed by string ID. This can be constructed either by using ReadStringTable, or manually (e.g. if you are not using Yarn Spinner CSV string tables but still want to use substitutions, format functions, and markup tags).
func LoadFiles ¶
func LoadFiles(programPath, langCode string) (*yarnpb.Program, *StringTable, error)
LoadFiles is a convenient way of loading a compiled Yarn Spinner program and string table from files in one function call. When passing a programPath named foo/bar/file.yarnc, LoadFiles expects that files named foo/bar/file-Lines.csv and foo/bar/file-Metadata.csv are also available. langCode should be a valid BCP 47 language tag.
func LoadFilesFS ¶
LoadFilesFS loads compiled Yarn Spinner files from the provided fs.FS. See LoadFiles for more information.
func LoadStringTableFile ¶
func LoadStringTableFile(stringTablePath, langCode string) (*StringTable, error)
LoadStringTableFile is a convenient function for loading a CSV string table given a file path. If stringTablePath is foo/bar/file-Lines.csv then it expects a corresponding Metadata file at foo/bar/file-Metadata.csv. It assumes the first row of both files are a header. langCode must be a valid BCP 47 language tag.
func LoadStringTableFileFS ¶
func LoadStringTableFileFS(fsys fs.FS, stringTablePath, langCode string) (*StringTable, error)
LoadStringTableFileFS loads compiled Yarn Spinner files from the provided fs.FS. See LoadStringTableFile for details.
func ReadStringTable ¶
func ReadStringTable(r io.Reader, langCode string) (*StringTable, error)
ReadStringTable reads a CSV string table from the reader. It assumes the first row is a header. langCode must be a valid BCP 47 language tag. In addition to checking the CSV structure as it is parsed, each lineNumber is parsed as an int, and each text is also parsed. Any malformed substitution tokens or markup tags will cause an error.
func (*StringTable) Render ¶
func (t *StringTable) Render(line Line) (*AttributedString, error)
Render looks up the row corresponding to line.ID, interpolates substitutions (from line.Substitutions), applies format functions, and processes style tags into attributes.
type StringTableRow ¶
type StringTableRow struct {
ID, Text, File, Node string
LineNumber int
Tags []string // Tags are set in the metadata table.
// contains filtered or unexported fields
}
StringTableRow contains all the information from one row in a string table.
func (*StringTableRow) Render ¶
func (r *StringTableRow) Render(substs []string, lang language.Tag) (*AttributedString, error)
Render interpolates substitutions, applies format functions, and processes style tags into attributes.
type TestPlan ¶
type TestPlan struct { StringTable *StringTable Steps []TestStep Step int FakeDialogueHandler // implements remaining methods // contains filtered or unexported fields }
TestPlan implements test plans. A test plan is a dialogue handler that expects specific lines and options from the dialogue system.
func LoadTestPlanFile ¶
LoadTestPlanFile is a convenient function for loading a test plan given a file path.
func ReadTestPlan ¶
ReadTestPlan reads a testplan from an io.Reader into a TestPlan.
func (*TestPlan) DialogueComplete ¶
DialogueComplete records the event in p.DialogueCompleted.
type VMState ¶
type VMState int32
VMState enumerates the different states that AsyncAdapter can be in.
type VMStateMismatchErr ¶
type VMStateMismatchErr struct {
// The VM was in state Got, but we wanted it to be in state Want in order
// to change it to state Next.
Got, Want, Next VMState
}
VMStateMismatchErr is returned when AsyncAdapter is told to do something (either by the user calling Go, GoWithChoice, or Abort, or the VM calling a DialogueHandler method) but this requires AsyncAdapter to be in a different state than the state it is in.
func (VMStateMismatchErr) Error ¶
func (e VMStateMismatchErr) Error() string
type VariableStorage ¶
type VariableStorage interface { GetValue(name string) (value any, ok bool) SetValue(name string, value any) }
VariableStorage stores values of any kind.
type VirtualMachine ¶
type VirtualMachine struct { // Program is the program to execute. Program *yarnpb.Program // Handler receives content (lines, options, etc) and other events. Handler DialogueHandler // Vars stores variables used and provided by the dialogue. Vars VariableStorage // FuncMap is used to provide user-defined functions. FuncMap FuncMap // TraceLogf, if not nil, is called before each instruction to log the // current stack, options, and the instruction about to be executed. TraceLogf func(string, ...interface{}) // contains filtered or unexported fields }
VirtualMachine implements the Yarn Spinner virtual machine.
func (*VirtualMachine) Run ¶
func (vm *VirtualMachine) Run(startNode string) error
Run executes the program, starting at a particular node.
func (*VirtualMachine) SetNode ¶
func (vm *VirtualMachine) SetNode(name string) error
SetNode sets the VM to begin a node. If a node is already selected, NodeComplete will be called for that node. Then NodeStart and PrepareForLines will be called (for the newly selected node). Passing the current node is one way to reset to the start of the node.