-
Notifications
You must be signed in to change notification settings - Fork 0
Flow
A flow is a concept to describe a continuous group of UiNodes for a specific purpose. To be precise, every UiNode or wizard containing other nodes, as well as every UiNode directly under the root element, will create a flow when executed. Therefore, there can be subflows nested in a big flow.
This article describes flows as the whole journey of a user interacting with libkinetic.
A flow covers all UiNodes directly under a UiNode group, such as <series>. Its user is any valid CommandSender, including the console, a player or other sender types.
Each user can only have one executing root flow at a time (with subflows inside this root flow). If a new flow is initiated on the same player, it will be scheduled to start after the current flow has completed. However, if the new flow is initiated with FLAG_EMERGENCY or FLAG_PRIORITY_INFO, the original flow would be put on hold (after the current UiNode of the original flow completes, unless the original flow has the FLAG_DISPOSABLE, which then will be terminated) and allow the new flow to execute first. Nevertheless, this behaviour of "putting on hold" may lead to instability and is not recommended.
Main article: Variable
A flow represents a variable scope. Variables declared in a flow's scope will retain until the flow terminates.
A flow can be started by explicitly calling the KineticManager::startFlow() function or declaring predefined entry hooks on the flow's owner node. The following are the predefined entry hooks:
A <command> element declares a command to enter a flow starting at the first node under a UiNode group.
The command name can be specified with the name attribute, and aliases can be added with <alias> child elements. The command name and aliases are configurable.
Variables can be set using command arguments if a mapping is set with the <arg> element. Each <arg> has a name, which is a user string , and an as attribute, which is the variable name that the argument value will get stored into.
Each <arg> can also be set as required or optional with the required="true"/required="false" attribute. If less arguments than required are provided by the user, an error will be sent without initiating the flow. If more than required are provided, the first optional arguments will be set in the order defined in the kinetic file. For example, if the <args> are declared as A b C d E, where A, C, E are required and b ,d are optional, and 4 arguments 1 2 3 4 are provided, the variables set are A=1 b=2 C=3 E=4 and d is not set.
There can be controllers to modify the command parsing behaviour. This flowchart shows the whole process of command parsing:
(receive command)
controller: ArgumentAssigner (assigner attribute in <command>, skips to CommandValidator)
for each <arg> {
controller: StringInputAdapter (adapter attribute in <arg>, default: arguments are parsed according to the type attribute in <arg>)
}
controller: CommandValidator (validator attribute in <command>)
(flow is created)
Each argument can have an adapter controller attribute that implements the StringInputAdapter interface to validate and parse the argument differently. In addition, the command can have an onCommand controller attribute that implements the AsyncRunnable interface, which is executed after arguments are preprocessed and before the node starts.
If an entry hook is deeply nested inside other UiNode groups, only the nodes inside the UiNode containing the entry hook are executed.
The nodes in the flow are not allowed to skip to any nodes beyond the UiNode. Calling break to any of the parent UiNode groups is equivalent to calling exit.
Standard flow controls like if, while, etc. could be implemented through onStart and onComplete handlers.
To implement an if, use a conditional onStart handler with onTrue="next" onFalse="complete". If multiple nodes are involved, wrap them with a <series> just like multiple statements in an if in PHP are wrapped with a pair of {}.
To implement a do...while, use a conditional onComplete handler with onTrue="start" onFalse="next". This is equivalent to a do{} while($condition) loop.
To implement a while, use a conditional onStart handler with onTrue="next" onFalse="complete" and the onComplete handler <always action="start">.