Creating a Lua mod
Before you start
To create a Lua mod in UE4SS, you should first:
- know how to install UE4SS in your target game and make sure it is running OK;
- be able to write basic Lua code (see the official book Programming in Lua and its later editions, or any other recommended tutorial online);
- have an understanding of the object model of the Unreal Engine and the basics of game modding.
How does a minimal Lua mod look like
A Lua mod in UE4SS is a set of Lua scripts placed in a folder inside the Mods/
folder of UE4SS installation.
Let's call it MyLuaMod
for the purpose of this example.
In order to be loaded and executed:
- The mod folder must have a
scripts
subfolder and amain.lua
file inside, so it looks like:
Mods\
...
MyLuaMod\
scripts\
main.lua
...
- The
Mods\MyLuaMod\scripts\main.lua
file has some Lua code inside it, e.g.:
print("[MyLuaMod] Mod loaded\n")
- The mod must be added and enabled in
Mods\mods.txt
with a new line containing the name of your mod folder (name of your mod) and1
for enabling or0
for disabling the mod:
...
MyLuaMod : 1
...
Your custom functionality goes inside main.lua
, from which you can include other Lua files if needed, including creating your own Lua modules or importing various libraries.
What can you do in a Lua mod
The API provided by UE4SS and available to you in Lua is documented in sub-sections of chapter "Lua API" here. Using those functions and classes, you find and manipulate the instances of Unreal Engine objects in memory, creating new objects or modifying existing ones, calling their methods and accessing their fields.
Basically, you are doing the exact same thing that an Unreal Engine game developer does in their code, but using UE4SS to locate the necessary objects and guessing a bit, while the developers already knew where and what they are (because they have their source code).
Creating simple data types
If you need to create an object of a structure-like class, e.g. FVector
, in order to pass it into a Unreal Engine function, UE4SS allows you to pass a Lua table with the fields of the class like {X=1.0, Y=2.0, Z=3.0}
instead.
Using Lua C libraries
If you ever need to load Lua C libraries, that have native code (i.e. with DLLs on Windows),
you can place these DLLs directly inside the same \scripts\
folder.
Setting up a Lua mod development environment
It is much easier to write mods if your code editor or IDE is properly configured for Lua development and knows about UE4SS API.
-
Configure your code editor/IDE to support Lua syntax highlighting and code completion. If you use VSCode, see here in Using Custom Lua Bindings.
-
Make sure that your build of UE4SS contains
Mods\shared\Types.lua
(a development build from Github releases contains it). This will load the UE4SS API definitions in your IDE. -
(Optional) Dump the Lua Bindings fromm UE4SS Gui console, and follow the recommendations to load them here.
Then open the Mods/
folder of your UE4SS installation in your IDE, and create or modify your mod inside it.
Applying code changes
The main benefit of developing Lua mods is that you can quickly edit Lua sources without recompiling/rebuilding the C++ mod library as is always the case with C++ mods, and retry without restarting the game.
You can either:
- reload all mods from the UE4SS GUI Console with the "Restart All Mods" button on the "Console" tab, or,
- enable "Hot reload" in
UE4SS-settings.ini
and use the assigned hotkey (Ctrl+R
by default) to do the same.
Your first mod
In the main.lua
file of your mod, write some code that will try to access the objects of Unreal Engine inside your target game and do something that you can observe in the UE4SS console.
You can start by trying just
print("[MyLuaMod] Mod loaded\n")
and once you have verified that it runs OK, you can start implementing some actual functionality.
The example code below is fairly generic and should work for many games supported by UE4SS.
It registers a hotkey Ctrl+F1
and when pressed, it reads the player coordinates
and calculates how far the player has moved since the last time the hotkey was pressed.
Note that the logging
The player coordinates are retrieved in the following way:
- Gets the player controller using UE4SS
UEHelpers
class. - Get the
Pawn
, which represents the actual "physical" entity that the player can control in Unreal Engine. - Call the appropriate Unreal Engine method
K2_GetActorLocation
that returns aPawn
's location (by accessing its parentActor
class). - The location is a 3-component vector of Unreal Engine type
FVector
, havingX
,Y
andZ
as its fields.
local UEHelpers = require("UEHelpers")
print("[MyLuaMod] Mod loaded\n")
local lastLocation = nil
function ReadPlayerLocation()
local FirstPlayerController = UEHelpers:GetPlayerController()
local Pawn = FirstPlayerController.Pawn
local Location = Pawn:K2_GetActorLocation()
print(string.format("[MyLuaMod] Player location: {X=%.3f, Y=%.3f, Z=%.3f}\n", Location.X, Location.Y, Location.Z))
if lastLocation then
print(string.format("[MyLuaMod] Player moved: {delta_X=%.3f, delta_Y=%.3f, delta_Z=%.3f}\n",
Location.X - lastLocation.X,
Location.Y - lastLocation.Y,
Location.Z - lastLocation.Z)
)
end
lastLocation = Location
end
RegisterKeyBind(Key.F1, { ModifierKey.CONTROL }, function()
print("[MyLuaMod] Key pressed\n")
ExecuteInGameThread(function()
ReadPlayerLocation()
end)
end)
When you load the game until you can move the character, press the hotkey, move the player, press it again, the mod will generate a following output or something very similar:
...
[2024-01-09 19:37:27] Starting Lua mod 'MyLuaMod'
[2024-01-09 19:37:27] [Lua] [MyLuaMod] Mod loaded
...
[2024-01-09 19:37:32] [Lua] [MyLuaMod] Key pressed
[2024-01-09 19:37:32] [Lua] [MyLuaMod] Player location: {X=-63.133, Y=4.372, Z=90.000}
[2024-01-09 19:37:39] [Lua] [MyLuaMod] Key pressed
[2024-01-09 19:37:39] [Lua] [MyLuaMod] Player location: {X=788.232, Y=-639.627, Z=90.000}
[2024-01-09 19:37:39] [Lua] [MyLuaMod] Player moved: {delta_X=851.364, delta_Y=-643.999, delta_Z=0.000}
...