exodrifter.space source code
exodrifter / unity-rumor Goto Github PK
View Code? Open in Web Editor NEWNarrative scripting language for Unity3D.
License: MIT License
Narrative scripting language for Unity3D.
License: MIT License
Consider the following script:
say "Pick a choice"
choice "a":
say "hello"
return
choice "b":
say "goodbye"
return
pause 60
say "Pick a choice already!"
choose
When a user chooses either the "a" or "b" choices, the 60-second pause will complete before jumping to the content of the choice, which is incorrect.
Instead, the pause should be terminated as soon as a choice has been chosen.
In Jinja2, variables can be substituted for their values using the following syntax:
variable has the value {{ variable }}.
Implement a similar variable substitution syntax to reduce the number of manual string concatenations.
In #61, a change was added to allow the use of keywords at the beginning of variable names. The way this was implemented was by checking for the existence of a space after the keyword. If a space did not exist, then the keyword was actually a variable. Otherwise, the keyword really was a keyword.
However, consider the following script:
$ some_binding(true)
Since the keyword true
is not followed by a space, it is interpreted as a variable with the name "true". This is not the desired behavior. Declaring variables with the same name as keywords should not be allowed from within the Rumor scripting language.
I have one running now, but it took me a while to setup a Unity project for the example -- would be great (for new users) to be able to just open a Unity project and press 'play' to see Rumor in action...
Add support for method overloading for bind methods.
For example, the following should be possible:
rumor.Bind("play", (string name) => {
Foo.Play(Resources.Load<AudioClip>(filename));
});
rumor.Bind("play", (string name, float volume) => {
Foo.Play(Resources.Load<AudioClip>(filename), volume);
});
However, Rumor fails with an ArgumentException
ArgumentException: An element with the same key already exists in the dictionary.
Strings drop accented letters and other symbols such as the em dash after compilation.
For example...
"I am — was — friends with Rød"
...becomes...
"I am was friends with Rd"
...after compilation, which is undesirable. Strings should contain all text contained within the quotes.
Add a way to fetch the content of the previously chosen choice. There are three ways this can be done:
Contextual
choice "'What brings you here, stranger?'":
say _choice + " Don't you know that it's dangerous around these parts?"
In this example, _choice
should have the value 'What brings you here, stranger?'
.
Method
choice "'What brings you here, stranger?'":
say _choice() + " Don't you know that it's dangerous around these parts?"
In this example, _choice()
should return the value 'What brings you here, stranger?'
.
Symbol
choice "'What brings you here, stranger?'":
say ~ + " Don't you know that it's dangerous around these parts?"
In this example, ~
is a reserved symbol that returns the value 'What brings you here, stranger?'
.
One of these examples should be added to Rumor to support this functionality.
See: reddit
Add support for -=
, +=
, /=
, and *=
.
It would be nice if all of the tests would automatically run whenever a PR is opened. This would help prevent issues from being introduced into master.
Dependent on #22.
Add support for Jinja2-like filters. For example:
{{ time | format("YYYY-MM-dd") }}
In Rumor, you should be able to do the following:
{{ format(time, "YYYY-MM-dd") }}
However, filters make it easier to read the string substitution since it places more emphasis on the variable, which is more likely to be named something that means something to the user, and less on the method that is modifying the variable.
Consider the following example:
using Exodrifter.Rumor.Engine;
using UnityEngine;
public class Test : MonoBehaviour
{
void Start ()
{
var rumor = new Rumor("$ foo(1)");
rumor.Bind<float>("foo", foo);
StartCoroutine(rumor.Run());
}
private void foo(float f)
{
Debug.Log(f.GetType());
}
}
This example fails to execute properly because of the performance optimization that removed the call to DynamicInvoke (#37), which automatically attempted to cast the arguments into the correct types.
The expected behaviour is the example should execute properly as if we were calling DynamicInvoke without throwing exceptions. Find a solution for this problem.
Trying to get your original example fully working in Unity, but get the error below when I click following 'Great!', before the apples and pears part (I'm likely doing something wrong):
ArgumentException: Cannot assign values to type Exodrifter.Rumor.Expressions.AddExpression!
Exodrifter.Rumor.Expressions.SetExpression.Evaluate (Exodrifter.Rumor.Engine.Rumor rumor) (at Assets/Libraries/Rumor/Expressions/SetExpression.cs:20)
Exodrifter.Rumor.Nodes.Statement+<Run>c__Iterator0.MoveNext () (at Assets/Libraries/Rumor/Nodes/Statement.cs:34)
Exodrifter.Rumor.Engine.StackFrame+<Run>c__Iterator0.MoveNext () (at Assets/Libraries/Rumor/Engine/StackFrame.cs:124)
Exodrifter.Rumor.Engine.Rumor+<ExecuteStack>c__Iterator1.MoveNext () (at Assets/Libraries/Rumor/Engine/Rumor.cs:307)
Exodrifter.Rumor.Engine.Rumor+<Run>c__Iterator0.MoveNext () (at Assets/Libraries/Rumor/Engine/Rumor.cs:285)
UnityEngine.SetupCoroutine.InvokeMoveNext (IEnumerator enumerator, IntPtr returnValueAddress) (at /Users/builduser/buildslave/unity/build/Runtime/Export/Coroutines.cs:17)
Add the no_wait enum argument as described in #42.
say "This line doesn't require an advance" no_wait
pause 0.5
say "And this line appears suddenly!
The use of no_wait
will cause the say statement to automatically advance itself instead of waiting for user input to continue.
Would be great to get minimal syntax highlighting (and possibly even auto-format) for RumorScript in popular editors (I'm using Visual Studio Code)
I'm prob missing something obvious here, but how do I do:
$ food = "cake"
say me "For lunch I had" + cake
The example does not showcase all of the features of the language, which can mislead users into thinking the library is not as capable as it really is.
Make the example showcase more of the language's capabilities, so that users can quickly get a better feel for what Rumor can do.
See: reddit
So I made a small modification to the script which causes an error, but I'm not sure why. Waht I was trying for, was for after the choice, in either case, to say "Now for fruit".
Am I missing something about the 'choose' command (maybe an explanatory error message would be helpful here) ?
label start:
say "Hi!"
say "Is this working?"
choice "Yes!":
say "Great!"
choice "No.":
say "Darn..."
pause 0.5
add "Maybe next time."
choose
pause 0.5
say "Now for fruit"
ArgumentOutOfRangeException: Argument is out of range.
Parameter name: index
System.Collections.Generic.List1[Exodrifter.Rumor.Lang.LogicalToken].get_Item (Int32 index) (at /Users/builduser/buildslave/mono/build/mcs/class/corlib/System.Collections.Generic/List.cs:633) Exodrifter.Rumor.Lang.RumorCompiler.GetKey (Exodrifter.Rumor.Lang.LogicalLine line, System.Int32& pos, System.Int32& depth) (at Assets/Libraries/Rumor/Lang/RumorCompiler.cs:174) Exodrifter.Rumor.Lang.RumorCompiler.GetChildren (System.Collections.Generic.List
1 lines, System.Int32& index, Int32 depth) (at Assets/Libraries/Rumor/Lang/RumorCompiler.cs:187)
Exodrifter.Rumor.Lang.RumorCompiler.CompileNodes (System.Collections.Generic.List1 lines, System.Int32& index, Int32 depth) (at Assets/Libraries/Rumor/Lang/RumorCompiler.cs:236) Exodrifter.Rumor.Lang.RumorCompiler.GetChildren (System.Collections.Generic.List
1 lines, System.Int32& index, Int32 depth) (at Assets/Libraries/Rumor/Lang/RumorCompiler.cs:191)
Exodrifter.Rumor.Lang.RumorCompiler.CompileNodes (System.Collections.Generic.List`1 lines, System.Int32& index, Int32 depth) (at Assets/Libraries/Rumor/Lang/RumorCompiler.cs:236)
Exodrifter.Rumor.Lang.RumorCompiler.Compile (System.String code) (at Assets/Libraries/Rumor/Lang/RumorCompiler.cs:151)
Exodrifter.Rumor.Engine.Rumor..ctor (System.String script) (at Assets/Libraries/Rumor/Engine/Rumor.cs:215)
ScriptedText.Start () (at Assets/Tests/ScriptedTextTest/ScriptedText.cs:14)
Consider adding enum arguments for some commands, such as:
say "This line doesn't require an advance" nowait
pause 0.5
say "And this line appears suddenly!
In this example, an enum argument nowait
is being provided to the say
command.
If a case can be made for the widespread, useful application of enum arguments, then this feature should be developed and made available. More examples of where this language feature would be useful would help in making this case.
(see: https://twitter.com/SenshiSentou/status/943220264132898816)
The line $do_thing("foo", 1)
gets (correctly) broken up into the following tokens:
do_thing
(
"
foo
"
,
1
)
However, when the first argument is an unquoted value ($do_thing(1, 1)
, $do_thing(true, 1)
) the comma gets appended to the value token (i.e.: a token of 1,
).
This can be verified by introducing an extra space before-hand: $do_thing(1 , 1)
. Conversely, calling $do_thing("foo",1)
without a trailing space results in a Unexpected tokens after string!
compiler error being thrown, though that might be intentional.
$ foo = coinflip() # returns 0 or 1
if foo == 0:
$ child = "boy"
...
throws the following error:
Exodrifter.Rumor.Lang.CompilerError: at (25,16): Unexpected tokens after string!
at Exodrifter.Rumor.Lang.RumorCompiler.CompileExpression (System.Collections.Generic.List`1 tokens) [0x006e3] in /Users/dhowe/git/tendAR/TendAR/Assets/Libraries/Rumor/Lang/RumorCompiler.cs:405
at Exodrifter.Rumor.Lang.RumorCompiler.CompileSay (Exodrifter.Rumor.Lang.LogicalLine line, System.Int32& pos, System.Collections.Generic.List`1 children) [0x00042] in /Users/dhowe/git/tendAR/TendAR/Assets/Libraries/Rumor/Lang/RumorCompiler.cs:593
at Exodrifter.Rumor.Lang.RumorCompiler.CompileNodes (System.Collections.Generic.List`1 lines, System.Int32& index, Int32 depth) [0x00106] in /Users/dhowe/git/tendAR/TendAR/Assets/Libraries/Rumor/Lang/RumorCompiler.cs:237
at Exodrifter.Rumor.Lang.RumorCompiler.Compile (System.String code) [0x001cf] in /Users/dhowe/git/tendAR/TendAR/Assets/Libraries/Rumor/Lang/RumorCompiler.cs:151
at Exodrifter.Rumor.Engine.Rumor..ctor (System.String script) [0x0000f] in /Users/dhowe/git/tendAR/TendAR/Assets/Libraries/Rumor/Engine/Rumor.cs:215
at ScriptedText.Start () [0x0000d] in /Users/dhowe/git/tendAR/TendAR/Assets/Tests/ScriptedTextTest/ScriptedText.cs:17
UnityEngine.Debug:Log(Object)
ScriptedText:Start() (at Assets/Tests/ScriptedTextTest/ScriptedText.cs:21)
this is more of a feature request and it might be totally out of the question, but I've noticed some redundancy when scripting where for example:
choice "I have a belly button."
say "I have a belly button."
the choice and the say are the same, what if I could do this instead
choice "Would you tell me more?"
say "~"
where the ~ was interpreted by the parser to replace it with the parent choice text
just a thought, it could be whatever symbol or I guess if it were a variable or something that could be used for both the choice and say option, but anyhoo.
this message will self-destruct in...
Rumor.CallBinding
uses DynamicInvoke
, which is very expensive. Since we already know all of the parameters beforehand, there should be a way to wrap the call to the delegate's Invoke
call, which is much faster.
The elif
and else
commands don't work if there are empty lines. For example, this script does not work:
if foo:
say "Hello world!"
elif bar:
say "Hello there!"
else:
say "Hello...?"
However, when the empty lines between the blocks are eliminated, the script works as expected. For example:
if foo:
say "Hello world!"
elif bar:
say "Hello there!"
else:
say "Hello...?"
The compiler should work even when there are empty lines between the blocks.
Unity has an experimental feature called Scripted Importers that allows a program to load file extensions not natively supported.
This feature will allow a user to save rumor files in a custom extension (like .rumor
) instead of .txt
. This will also be useful for #50, #51, and #52, since syntax highlighting is often automatically enabled based on the file extension.
For now, this feature should just import any .rumor
files into something similar to a TextAsset
. In the future, it may be possible to do more complex things like precompile the script.
Add the cant_skip enum argument as described in #42.
pause 0.5 cant_skip
The use of cant_skip
will cause the pause statement to always wait the full amount of time specified instead of continuing as soon as the user advances the script.
The SerializeRumorScope
serialization test is broken in the ".NET 4.x Equivalent" scripting runtime version. It should work in all scripting runtime versions.
I actually messaged Unity about this issue a few months ago (response included in the next comment). There might be other serialization cases that are broken due to the same assumption I may have made in other parts of the library, so a thorough check may be in order.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.