Lua Script plugin

I started this plugin as learning project. It is based on ideas from the Engine script plugin and also the Javascript plugin by ncsoft.

The purpose was to work my way through some use cases for scripting with Lua. I also decided to use SWIG for the wrapping of Engine classes and to provide a runtime.

The first use cases was something like this:

  • Spin my own Actor and use Vectors and Rotators (Math/Vector)
  • Spawn Actors and use the Class Asset editor functions.
  • Trace in world, using HitResult.
  • Draw trace debug information and also use Colors
  • Spawn emitters from Assets defined in the editor.
  • Access the Components in the Actor - Change color of the Material in the Mesh.

The Lua script to do this looks like this:

And the result:
[video]https://www.frostyelk.se/plugins/unreal/lua/LuaScriptDemoArne.mp4[/video]

Not sure where I will go from here but so far I have learned a lot of the engine functions.
Maybe wrap the Pawn/Characters/Controllers and do some fun stuff.
I will probably have a look at Events to see what should be a natural way to script for that.

Some more progress.

I had a look at events to see how you would want to use them as a scripter.
One way could be to just declare a function with the event name and you are good to go, the other method would include subscribing to any event with a listener.
The fully dynamic solution would require the scripter to know the internals of the events, e.g. the BP event Hit is called via delegate “OnActorHit”.
I decided to test the hardcoded version with a simple “EventHit” function that is called whenever the Actor triggers the event. So the Lua code will look like this:


function EventHit(hitActor, otherActor, normalImpulse, hitResult)
    print("Lua function EventHit()")
    print("Hit Actor: " .. hitActor:GetName())
    print("Other Actor: " .. otherActor:GetName())
    print("normalImpulse: " .. normalImpulse:ToString())
    print("hitResult.BoneName: " .. hitResult.BoneName)
    print("hitResult.Location: " .. hitResult.Location:ToString())
end

Next I wanted a workflow that is more “programmer” like than visual coding with BP but still not as complex as C++. I really like the tools from JetBrains so I choose to use IntelliJ as the base.
IntelliJ has no builtin support for Lua but the Lua plugin seems good.
I like the simple way to refresh and start VS from the main menu so I added a similar function for Lua:
LuaProjectMenu.png
The Refresh action will make a very basic code completion file for the Lua plugin. Setting up the complete IDEA folder structure could maybe be a next step.
The Open action will start a predefined installation of IntelliJ pointing to the project.

When a Lua project gets bigger and more complex you need a way to structure it. So my next investigation was into Lua modules, both your own but also ready made packages.
As all Lua code must be self contained in an asset the modules needs to be handled the same way.
The Engine script plugin uses the Blueprint magic to handle this but as I’m not yet an engine magician I choose to simply use the component for the modules.
The downside is that the Actor BP needs a manual compile to load the Lua modules, I have not found a way to trigger the BP as dirty from inside the Actor.
So after checking a script component as a Lua module:
LuaModules.png

Now you can use the standard Lua function to include a Lua module:


require("ActorUtils")
print("Just loaded a module")
MeshUtils.SetMeshColor(MyStaticMesh, ue.Color.MakeRandomColor())


In the Lua module (ActorsUtilities.lua):


MeshUtils = {}
function MeshUtils.SetMeshColor(mesh, color)
    print("Setting Color")
    local dynamicMaterial = mesh:CreateDynamicMaterialInstance(0)
    local linColor = ue.LinearColor(color)
    dynamicMaterial:SetVectorParameterValue("ColorScreen", linColor)
end

Finally to summarize the currently SWIG wrapped Classes/Functions:
Actor, ActorComponent, Color, DrawDebug*(), FileHelper, GameplayStatics, HitResult, LinearColor, MaterialInstance, MaterialInstanceDynamic,
Matrix, MeshComponent, Object, Paths, PrimitiveComponent, Quat, Rotator, SceneComponent, StaticMeshComponent, Transform, Vector, Vector2D, Vector4, World

Strings and numbers are converted from FString, FName, uint32, float, etc to use standard Lua strings and number types.

This is cool; I did the same for learning purposes, but with the BASIC language which I like. But I have zero interest in finishing it haha

Very cool. Really wish UE4 had something like this in it already.

Looking forward to more progress!

All of my yes! Lua is my language of choice for just about anything, so this is really good news.

Do you have any plans to release the source for this any time soon? I would really like to start messing around with this.

The code is in extreme flux as I use this as training project but if it proves to work in the end I would probably put it up on GitHub.

So for the next exercise I wrapped Pawn, Character, PawnMovementComponent, SkinnedMeshComponent, SkeletalMeshComponent, InputComponent and CharacterMovementComponent.
With this I could make a bot that runs around the map.
Hook up the Lua script to a Character:


and write some code. Run Forrest, run…

Alright, I can understand that.

Something I would really like to see, though I understand how technically complex this is, is the ability to define custom inherited classes / components from Lua (like Blueprints), perhaps with the ability to Blueprint those classes. Pure wishful thinking though, you understand.

A lot of people that would really love a decent LUA plugin.
Problem is support beyond initial release.
Release or not, keep it up :slight_smile:

Very nice! I would love to see this

Would it be possible to create a blueprint Lua node so we can define logic inside the node. This would help quickly script logic inside existing blueprints instead of dealing with lots of nodes

E.g. double clicking the BP Lua node would open up the editor with an empty lua function in it. When you save it, it would parse the function parameter list and create input / output pins in the BP node

Do have any use case or workflow example for this? Now the Lua script is an ActorComponent with ‘this’ set to it’s owner so the script think it’s an Actor with the owners components exposed as globals to the script.

I guess you are looking for something like the Lua Blueprint Extension plugin.
I have looked at that plugin as well and it targets a deeper integration with BP. One of the problems when moving in and out of Lua is that you need to convert the complex data types of UE. The Lua BP plugin supports only the basic types, I found that most of the time you work with more complex types.

From a workflow perspective you can just add a Lua Script Component to your BP and write the code in the IDEA.

Essentially a halfway point between C++ and Blueprints. You’d subclass a Component or Actor (and somehow tell UE4 that you did), set it up, define functions, etc.

For example (with self referring to the instance of MyActor the functions are being called on):




-- Class declaration function
Class 'MyActor' (Actor)

-- Or other constructor name, e.g. __init
function MyActor:MyActor()
    self.SubComponent = ConstructorHelpers.CreateDefaultSubobject(self, ActorComponent, 'TestComponent')
    self.RootComponent = self.SubComponent
end

function MyActor:Tick()
    -- Do something with our SubComponent.
end



Doing full inheritance with both C++ and BP seems like a larger job. The Lua component assumes the role of it’s owner so from the script point of view it is an instance(this/self) of the owner class. So i.e. creating and attaching other components is possible.

Yeah, I know. It’d need to be integrated very closely to work as well as Blueprints. It’d essentially be implementing a clone of Blueprints, albeit sans custom editor.

Well, in that case, wouldn’t it be possible to also create an inheritable UCLASS that handles this? I know this isn’t really possible in a BP, but for example:
(Pardon my off-the-cuff C++.)




UCLASS()
class AMyActor : public AActor, public LuaScriptExecutor
{
// class ...
}



So for BP-only projects, you can use the component, but for C++, you can simply inherit from the class. Now, you’d need to explicitly call methods (tick, etc…) from the derived class, but it seems an acceptable tradeoff.

Just an idea, of course. Not entirely a fan of solely having to use components.

Finally found out how to bind a Lua function to an Event. A challenge was that the event could have any number of parameters of any type. I also wanted this to be fairly simple to set up in the Lua script.
The Lua script can now bind to an event with BindEventFunction(Object, "EventName, “LuaFunctionName”), I guess I could make the Lua function name type safe but I went for strings now to start with.

The test case assumed that you for some reason wanted to set a players head on fire when he passes a trigger volume. A standard Trigger Volume was placed in the map and should be controlled from the Level BP.
It turned out that Level BPs don’t attach Components so that has to be done in the BP BeginPlay. For the Lua script to get hold of the trigger volume I tested to make a BP-node that exposes any object with an optional Lua notify function.

The Level BP looks like this (The first event is just for reference, it triggers before the Lua script:

The Lua script:
LevelLuaScript.PNG

Burn baby, burn…

Hi OP, my UE4 script plugin doesn’t compile right and I heard some threads said Epic already cancelled Lua support, I’m starting my own Lua plugin now.
I have basic knowledge of Lua C api and some other tools like tolua++.
But I can’t quite imagine how the architecture of a c++/lua/blueprint workflow would be like. Can you give any advice how you designed the structure?

it look so good.
Hi, i try to build the lua Script, i had build the lua.sln and have lib in Lib\Release\win32(win64), but when i build the ue4.sln , have link error like:void __cdecl LuaRegisterExportedClasses(struct lua_State *)" (?LuaRegisterExportedClasses@@YAXPEAUlua_State@@@Z), public: virtual bool __cdecl FLuaContext::Initialize(class FString const &,class UObject *)" (?Initialize@FLuaContext@@UEAA_NAEBVFString@@PEAVUObject@@@Z)

what happen?

hi guys,I have make a similar one,It’s simple and works fine.Lua 5.1 codegenerator for UE4 - Community Content, Tools and Tutorials - Unreal Engine Forums.