Scripting Language extensions via plugins

Hey guys, I wanted to share with you what I’ve been working on recently: as some of you have already noticed, I did a few check-ins into the master branch with plugins that should make life easier for anyone who wants to add their own scripting language integration to the engine. There’s even experimental Lua support as an example how to use/extend those plugins.

The main goal behind this is to provide a common entry point for anyone who wants to add scripting support to UE4 without having to modify the engine itself. It also shows how to use UE4 reflection system to automatically generate C++ glue code.

The basic principles how it all works are quite simple:

There’s 3 plugins:

  • **ScriptGeneratorPlugin **(SGP) - this is used to extend UnrealHeaderTool (UHT) functionality and generate scripting language C++ glue code using classes already generated by UHT.

  • **ScriptPlugin **(SP) - this is the main Engine-side plugin. This is where the glue generated by SGP is going to be compiled. Cool thing about this is that you don’t really need to include any generated code there, it’s automatically picked up by UBT! All you need to do there is to link it with the scripting language library you want to use and provide functions you might have used in SGP-generated code + maybe some additional script-specific code with helper functions etc.
    It also defines:

  • *UScriptComponent *- contains the main entry point of execution for the scripts. More about that later.

  • *UScriptAsset *- this where the script source/byte code goes and is read/compiled from

  • **ScriptEditorPlugin **(SEP) - editor-side plugin, it’s very simple and it’s main purpose is to provide editor factories for importing scripts into UScriptAssets.

When writing this, I used Lua as proof-of-concept integration. If you want to test how it works, the only thing you need to do is to download Lua source code and copy the entire lua-5.2.3 folder (except luac.c) into Engine/Plugins/Script/ScriptPlugin/Source/ScriptPlugin, then re-generate projects and compile the engine. UBT should automatically pick this up and enable Lua integration. Note that I’m not a Lua expert and I used it because it was free/cross-platform/open and quite easy to get started with. I bet there’s people with more Lua knowledge in the community who can point out all the mistakes I did, please do!

So the idea behind UScriptComponent is that you can add it any actor and assign a UScriptAsset to it in the editor. It then initializes scripting in UScriptComponent::OnRegister(), ‘ticks’ scripts in UScriptComponent::Tick() and calls destroys script objects inside UScriptComponent::OnUnregister(). It assumes there’s pre-defined functions declared in script: Tick() and Destroy() which are called in UScriptComponent::Tick() and ::OnUnregister() respectively. For Lua integration the global scope script is called when the script is loaded in OnRegister. At that point the script context class determines if Tick() is actually defined and if not it’s not going to bother calling it. Here’s an example how Lua script would look like (sorry it’s so brief but I didn’t have time yet to come up with more elaborate examples):


print("Lua in UE4!")
TickCounter = 0
Mesh = UE.LoadObject(StaticMesh.Class(), "/Engine/EngineMeshes/ParticleCube.ParticleCube");
function Tick()
	TickCounter = TickCounter + 1
end

function Destroy()
	print("Destroy Lua script")
 	StaticMesh.Destroy(Mesh);
end

In the default case where Lua is not enabled, SGP uses a generic script generator which exports simple wrapper functions around public class members.

We’re probably going to be polishing this in the next two weeks a little bit, we’re also working on simplifying UHT a lot so stay tuned for more updates. I’ll probably do a blog post about this in the near future too.

2 Likes

Awesome Job Robert! The work you guys put into UE4 means you have a passion too do so! :smiley:

who rated Robert’s work at 4 stars?

Robert you get 5 stars from me!

:slight_smile:

1 Like

Absolutely amazing work. This is the true power of open source.

Cheers!

I have to say this really solves many of my issues with mono integration.

this looks great. Fantastic!

This is very cool ! How complete is the lua proof-of-concept?

Can’t wait until UE4 gets scripting, it’s one thing I miss coming from Unity.

Very cool! C++ & blueprints are more than enough for my purposes but this is still very awesome news for those looking for this! :smiley:

But… blueprint is scripting system. What makes you feel that “attach script to actor” way is better than what is provided via blueprints? Taking to account you can write your logic on both C++ and blueprints for the same objects.

Blueprints are good for small things but in my personal opinion, it’s much more comfortable to work in a scripting language for rapid changes and development. C++ isn’t a substitute for a scripting language, both compile-test times and development time wise.

I know there are a lot of people around here from some seriously old schools of thought, so I’m not going to try convince anyone that scripting is a good solution. In my opinion it is a very good way to develop.

Thanks a lot for this brilliant plugin Robert!

I do have a question tho’, how would I go about preventing the script from running inside of the editor?
As soon as I place an actor with a lua script into the world, the script will continue to Tick forever until I reload the map, any idea?

How did you get the script to execute in the first place if you don’t mind me asking

Hello Johnny,
I defined WITH_LUA and WITH_EDITOR in my project and re-built the plugin, (not necessary!)
as for getting it to execute, that is pretty simple:

  1. Make a blueprint actor,

  2. attach a ScriptComponent

  3. Write a script file (.lua or .txt)

  4. then drag and drop it into your Editor,
    it will then automagically make a ScriptAsset with a path to your script file

  5. In your Blueprint, select your ScriptComponent and assign your newly created ScriptAsset to it.

Now you are free to play with the script, pretty simple?

You can continue to edit your script.lua/txt file,
to see the changes just reimport the ScriptAsset:

  1. open your scriptasset
  2. on the menu, click “asset -> reimport”
    it then will recompile the source into bytecode,
    it’s really quick, takes less than a second to make changes to a script!

Hopefully that will get you going :slight_smile:

Cheers.

Sweet, got that working now. Trying to figure out what I can call, and what I can’t call at the moment.

It should automatically define WITH_LUA in the plugin module rules if you copy the lua folder to its source folder, like I described in the first post. Didn’t it work for you?

I fixed that in the master branch (b0496895bee05b0f5febbc23f67e079f8d0af1b3)

Sounds great! Thanks for plugin! :slight_smile:

Well, it doesn’t export property wrappers and I’ve not tested it yet with more complex scripts. There may be some issues with object ownership.

Awesome, I was planning on implementing Lua as a proof of concept for some stuff already, really glad you chose Lua as the example as its a very powerful scripting language.

Is there going to be any sort of documentation in the near future for this?

Sure, I’m going to write a blog post with more details next week.