MiniScript: lightweight scripting language for your game

EDIT: MiniScript is now available in the asset store!

(I’d posted about this in the General forum, but realized that this is probably a more appropriate place for it.)

I have been working for the last couple of months on a lightweight scripting language called MiniScript. It can be described fairly completely in a single page of documentation, so it is very easy to pick up and learn. And because it is written entirely in C#, it is trivial to embed in a Unity app.

MiniScript source code is compiled down to a bytecode, which is then run through an interpreter. You can tell this interpreter how many milliseconds to run before returning, and then have it pick up right where it left off in the next frame. The set of intrinsic functions even includes a “wait” command that lets a script pause for any number of seconds — all without causing a hiccup in the host game!

Feature highlights:

  • clean syntax without a lot of unnecessary punctuation
  • robust list, string, and map handling
  • object-oriented
  • safe (completely sandboxed)

Even though it’s fully sandboxed, it’s easy to integrate with your Unity objects. Unity code can simply reach into the context of any script, and get/set variables as you wish. Or, you can add new intrinsic functions, or entire classes, to the script environment.

I’ve put up a web demo that lets you play around with the language yourself — either in a read-eval-print sort of mode, or by writing a little script and running it. In either case, you have access to a “ship” map with x, y, and rot properties, that controls the position and rotation of a sprite on the screen.

I’m looking for feedback on the language design, as well as (of course) reports of any bugs you may find. In addition to the quick reference page, the demo page also includes a link to the regression test suite. That contains hundreds of lines of MiniScript code and the expected result, so that’s a good source of example code too.

I’d also love to hear any thoughts you have about how you could use a scripting language like this in your games (or other games you love).

Please give it a try, and let me know what you think!

Asset Store link

7 Likes

Looks like great work Joe. I’ve often thought about making a little scripting language to handle events and such. Will be sure to check this out when I return to Unity dev next year.

1 Like

Seems useful.

But that “end for” statement… :hushed::rage::(:eyes:

Go the Python path and just infer it from the indent.

Thanks!

Goodness gracious, no! :stuck_out_tongue: I understand the pros and cons of it, and it was an interesting experiment that somebody needed to try… but now we’ve tried it and seen the grief it causes; we can do better than that!

I would consider replacing end for with next if there were enough clamoring for that… but since we’re already using end while and end if, I like the consistency of end for. No need to guess; the end token is always just end plus the opening token.

3 Likes

This prompted me to look for a poll. It seems we indent-based nesters are outnumbered by curly-bracers :frowning: (about 2 to 1): http://forums.xkcd.com/viewtopic.php?f=11&t=38636

Note that indent-based nesting is still the second-most preferred though; much more so than the “end”-style used in Lua, anyway. (I doubt the actual difference is that extreme, as it was a small poll, but the results are still worth considering)

My favorite is actually for indent-based nesting to be the default, but for curly-braces to be allowed to used, if they are given.

Best of both worlds. Indent-based nesting is fine most of the time–you just drop the braces; but single-liners (or weirdly-indented blocks) are still able to be written if desired, simply by having the next non-space char be a curly brace.

The problem with Lua’s “end” closer is that it’s too unspecific; you can’t quickly tell what it’s the end to (unless the user adds a comment, but that’s just expecting the user to work around a flaw in the language design — which most users, being lazy, will not do anyway).

This is not only a problem for the human reader of the code, but also for code editors (i.e. software for editing code), which can very easily get confused about what matches up with what as code is inserted or deleted. With proper (strongly matched) block closers, the editor can keep things matched up and indented even when things are in a half-edited state, and correctly show which block is still missing its closer (or which extra closer has no opener) most of the time. (The REALbasic code editor works this way — and it’s way better than any other editor I’ve ever used in this regard.) It’s also a problem for the parser, when it comes to reporting a sensible error message when things are mismatched. Messing up one closer (or opener), and suddenly matching ifs with end-whiles and fors with end-functions and so on, all the way down to the end of the method (or the file!), is just stupid — it’s amazing we put up with it!

Note that curly braces have exactly the same problem.

This cascading-mismatch problem is one of the motivations behind indent-based blocking, but that brings a whole host of problems of its own. Using specific words (for/end for, while/end while, if/end if) is a simple, clear solution that solves all the problems, creates no new ones, and is easy to read. The only drawback is that it’s a little more to type, but in the course of a program it’s a very very minor increase.

(Well, the other drawback is that, due to the current dominance of C-derived languages, it is nonstandard… but that is just a historical accident, and I can’t bring myself to perpetuate a clearly worse solution just because it is common. And yes, I type in Dvorak!)

1 Like

That’s a good point. I do think it becomes less of a problem as our compilers become “smarter”, but I have seen cases where it still comes up. (I think for the major IDE’s, for example C# in Visual Studio 2015, it’s mostly a non-issue nowadays, because you instantly see the red underlining when you mess up a brace, and just correct it; but for basic text-editors like those possibly used in games for scripting, that could be a significant annoyance)

From my coding in Python for a few projects, I didn’t actually notice any major issues/annoyances with the indent system, but perhaps I just didn’t go deep enough to run into them. (the main project was a model/animation exporter for blender)

On this point I wholeheartedly agree. (Very cool that you type in Dvorak!)

I really respect people thinking through an issue and sticking with what they see as the best long-term solution, even if it might not be ideal in terms of ease of transition/practical usage for some time. In this case I disagree with your conclusion, but I very much support the reasons you hold to it.

As a side-topic, I feel a similar way about our world languages. There are many inefficiencies that we could remove if we just had our schools gradually shift the rules they teach, but instead the people writing English books tend to actually perpetuate bad rules just because it’s a little more in-synch with how people currently talk and write (or how the last generation did anyway). Really disappointed that cirriculums haven’t been taking up the job of introducing improvements to our language.

1 Like

Hey everyone, I’ve just posted Robo-Reindeer Rumble, a programming game built around MiniScript. Please check it out!

The problem with having specific closings or even just word closings becomes obvious with closures or certain coding styles. It’s why ruby supports both ‘end’ and braces. specific closing tags just make your code much more difficult to read with a sufficiently powerful language. For a very simple language I think it’s ok.

I’m curious what kind of parser are you using for this?

1 Like

It’s a recursive descent parser.

I’ve been toying with the idea of using something like this for controlling npc behavior in an open world building game I’m working on. I wanted something addicting that people could spend hours tweaking, and a way to make their part of the world unique.

The issue I run into is that what I really want for players looks more like a DSL. I think a good DSL presents itself as something that even non programmers could use, because they can actually read it and have an idea of what it does at the very first glance, without any previous programming experience. Now it’s still logic and they have a learning curve, but I’m thinking it would get a lot more people to actually try it.

For example Cucumber lets you specify a lot of fairly complex logic using standard english. A lot of testing tools now take the approach of using easy to read words appended in dot notation that become phrases anyone could look at and have a good idea of what it’s doing even if they are not developers.

So if the problem is one of I want to give players more power and functionality they can spend hours in, then I don’t know if just a simpler general purpose language solves that problem well. Because I think the biggest barrier is actually that it looks and feels like a programming language. Now if you are out to teach people to code that’s a different story.

And all of this kind of raises the question of whether any language is really the right approach, or do you just encapsulate the functionality you want to give in a UI. At the end of the day most likely there are just specific things players want to do, and those things can most likely be expressed in a UI. And that makes it even more accessible.

Yes, I think you’re right. If you really want to encourage participation of non-programmers, and there’s any way you can structure the problem so that you can fit a reasonable UI over it, you’re best off doing that (even if it compiles down to code behind the scenes).

For something like that, behavior trees are another possible way to go (which are really just a very constrained form of scripting).

Then there’s the in-between approach of having code, but wrapping it in little puzzle blocks you drag around and snap together, like Scratch, or pretty much any of the Hour of Code exercises. This is becoming such a common metaphor that many people will recognize it right away. It’s a slow way to write code, but has the big advantage that syntax errors become pretty much impossible. (MiniScript could serve nicely as the backend layer for something like that.)

I like this idea, I haven’t thought about it much before, but it would be fun to put small programming type of puzzles in games and see how they manage with it.
Actually I just remembered minecraft, it had simple logical elements, but with an “if-branch” block and an “integer-memory” block you could do a lot more with fewer block. Someone should make this xD (At least as a demo)

I myself wanted to write a lightweight in-game scripting language, but mostly because I wanted to test behaviors in bigger projects on-the-go. Recompilation is such a bother…
Also imagine if you could execute function calls from within the editor, that would be cool, actually I know how I would make this (just make the same editor gui window for selecting functions, as the one the Button components has), but I’m too lazy lol

Btw is your mini script open source? I’d like to take a look if you don’t mind.

Yeah, lots of open-world games have some sort of scripting… Second Life has LSL, etc.

Yep, and not even possible on the user’s machine. So, with a scripting language built into your game, you could distribute updates (fetched via the WWW class or whatever) that actually change the behavior of the game.

It’s not open-source, exactly, because I plan to sell it via the Asset Store. It won’t be too pricey, but I can certainly spend more work time on it if it’s bringing in at least a little revenue! However source will be included with the package, and it will probably end up open-source eventually.

It seems to be quite solid now, but I still have a fair bit of code clean-up before I’d be ready to distribute it widely. But PM me if you want to have a sneak peek.

Meanwhile, be sure to try Robo Reindeer Rumble… somebody needs to knock my “Charger” script off the throne!

My general idea was to make a launcher program that checks for updates before starting, since that would also update other assets.
But your solution would be faster, since you could make a WWW request and get the new logic while the user is i the menu.
It would even work in mobile games.

And I was just interested if you’re using System.Linq.Expressions or something else?

Yep!

Something else. It’s a completely custom parser, bytecode compiler, and runtime engine. See the MiniScript Quick Reference for an overview of the language.

A small update: I’ve added a new shuffle intrinsic, as a method on lists and maps, which randomly permutes the values. (In the case of a map, this means that the mapping from keys to values is randomized). For example, you could try:

x = range(1,10)
x.shuffle
print(x)

Also, under the hood, I did a small but important optimization in assignment statements, eliminating a temporary variable and making them one step shorter. Since typical code has a lot of assignment statements, this is a good win. I plan to do a few more optimizations before the official release.

The demo and game have been updated, as has the quick ref document.

One of my pre-release testers has gotten a MiniScript REPL (read/eval/print loop) working in a Hololens project:

Very cool!

2 Likes

Interesting, looks like the language can have nice real-life usages.

REPL systems go well with simple scripting languages, although I’m having much more fun with using C# REPL in the editor, since it’s so easy to interact with the rest of the code and you get to use all the language features.
Have you tried using Mono’s C# evaluator?

I’ve been wanting to make my own simple scripting language for quite some time but I have no idea how I would go about to make sure the formatting is correct and read values. Since you’ve got a start here, I assume you know a bit on how to actually do that. So do you have any resources I could use to try and make something like that?