Moho: a Rust-based code generator for UE C++ codebases

It’s another week and we have another tool! This time around, it’s moho (Spanish for “rust”), and it’s a code generator. You put in some effort to write a class draft, and then it translates it to boilerplate! Here’s an example:

class ATestActor : AActor
{
    [EditAnywhere, BlueprintReadWrite]
    {
        [Category="Object References"]
        {
            [Description="A nice long description goes here"]
            AAnotherActor* AnotherActor;

            [Description="Ugly af"]
            AYetAnotherActor* YetAnother;
        }

        [Category="Settings"]
        {
            [ClampMin = 10, ClampMax = 15]
            float MaxHealth = 10;
        }
    }

    [BlueprintReadOnly, Transient]
    {
        [Description="Read only var"]
        bool IsTrue = false;
    }
}

This is a draft of a class that extends AActor. Within the draft, we have blocks and fields, and both can have properties. The only point of blocks is to pass their properties to all of the fields inside, so that we don’t have to write boilerplate! Once this is done, run moho -r <folder> and you’ll get a source and header file with exactly what you’d expect inside (hopefully).

Here’s the repo, have fun with it, and hopefully it can help you not have to copy-paste code around! Oh, and there’s an exe version in the release. On github. Right here: https://github.com/devlike-code/moho/

This tool was commissioned by a friend of mine, annoyed at how boilerplatey his workflow was. He was tired of doing this through shell and/or python scripting, and wanted to dedicate 2-3 weeks to doing it in C++. I am certain that he underestimated it, and even then it took 2-3 days in Rust and overachieved: it’s very modular, can easily be used for many things even without recompilation, and is snappy as hell. As described in the readme, moho is three separate parts in a trench coat, navigating the world in sync: a parser, a scripting engine, and a templating engine. While the input language is predefined, it’s very loose in that it describes some named unit for typed, named value fields. The unit inherits its code structure from a superunit, lending itself to the result: a class extending a superclass. The choice of superunit dictates what the result looks like: if the superunit’s name exists as a .rhai script file, it’ll be called to interpret the request. If not, a base.rhai is called, although it does nothing useful.

The scripting done in Rhai (found here: http://rhai.rs) isn’t directionless: there’s a couple of objects registered to guide the execution. Most importantly, an output logger called Output can be used to add text to the output, or create parts (templated sub-outputs) and snippets (sub-logs) that can be embedded into the larger whole. These three concepts make templating in moho a breeze: you don’t need to append a string out in the wild: make a text file with the content you want and a bunch of holes (written like {{this}}), load it into your script, fill the holes with variables or other templates and produce a complex result with no pain.

Can’t wait to see how this will be used in the wild, and I’m honestly surprised it didn’t already exist: we seem to be bogged down and scared of how slow our development is. I think the responsible party is C++ on one side and the idea that if you want a small tool to do things like these, you need to throw caution to the wind, rid yourself of a type system and go native – python, shell, something that you’ll quickly grow to hate as it goes on. I honestly think that in the same 2-3 days, I would have had a good enough cmake file to start developing with. If you don’t agree, I think the point is even clearer: we need to find that culprit and fast.


Posted

in

, ,

by

Tags:

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *