IntroductionLScript for Unreal is a simple and full integration of Lua with the Epic Unreal game engine. It has been integrated without problems into many versions of "Americas Army: Operations" and "Unreal Tournament 2004".
To take full advantage of the Unreal engine via LScript an Engine package has been added to the basic Lua interpreter. The Engine package adds these functions, which can be accessed from either a Lua script or the Lua console: CloseConsole, Dump, DumpClass, FindFirst, FindFirstAActor, FindNext, FindNextAActor, FullName, IsA, Load, Log, New, OpenConsole, Restart
The source code is distributed without licence though a credit would be nice: Picklelicious, Temp2 and SmokeZ. Enjoy. LScript for Unreal connects a Lua scripting engine up to the Unreal game engine. It allows you to do things like:
PC = Engine.UObjects['StudentController Entry.StudentController'] PC.Region.Zone.bDistanceFog = false Rot = Engine.New(Engine.UObjects['Struct Object.Rotator']) Rot.Pitch = 1024 Rot.Yaw = 0x8000 PC.SetRotation(Rot) PC.ConsoleCommand('exit') Canvas.DrawText('Hello!') Canvas.DrawText(PRI.PlayerName)Lua is a scripting language designed for extending applications. You can learn more about the Lua scripting language here: www.lua.org
CompilingYou can compile this project with gcc (Makefile.win) or use Dev-C++ (LScript.dev) or with VC6 / VC7 (LScript.dsp, LScript.vcproj, LScript.dsw, LScript.sln)
Source CodeLScript for Unreal's source code can be found in SourceForge here: http://sourceforge.net/projects/lscript4unreal/
How to build LScript
1. Download the latest Lua source code from the Lua site. 2. Copy all the files from lua-x.x/src directory into your build directory. 3. Delete the lua.c and luac.c files. 4. Copy LScript.cpp and the appropriate workspace file(s) into the build directory. 5. Create a project that includes all the files in the build directory. 6. Build it.
HitoryPicklelicious thought it would be fun to try and hook Lua up to the AAO 2.6 engine, and then see if he could write some useful Lua scripts (LScripts) instead of Unreal scripts (UScripts). Temp2 and SmokeZ ported, created hooks for newer versions and kept it going.
One of the nice thing about Lua scripts is that they are simple to create. You only need a text editor (no SDKs or compilers).
Lua ConsoleLScript can display an interactive Lua interpreter in a console window. Pressing <Alt>+c will open and close the Lua console. It is easier to use the console while playing the game in windowed mode.
Clicking the X (close button) on the Lua console will close the entire game. Sometimes the Lua console will not be responsive to keystrokes. If this happens closing and reopening the console with <Alt>-C will fix the problem.
The Lua console is very similar to the game's console. You can type in any Lua commands here. It is a good way to try things out before adding them to your scripts. If your script is in a file called "test.lua", you can load it from the Lua console like this:
Engine.Load('test.lua')You can totally restart (which loads default.lua too) with <Alt>-R which is equivalent to the Engine.Restart() command. <Alt>-L will display the LScript log file default.log
A useful thing to do is to size the console to whatever size you want, right click, select properties, layout tab, and then set the Screen Buffer Size to whatever you like. Picklelicious likes a lot history, so set his to Width:124 and Height:2048.
Default.luaDefault.lua is the default script. The Lua interpreter will load this script during its initialization.
Engine PackageLScript has added an Engine package to the basic Lua interpreter. The Engine package adds these functions, which can be accessed from either a Lua script or the Lua console:
CloseConsole Dump DumpClass FindFirst FindFirstAActor FindNext FindNextAActor FullName IsA Load Log New OpenConsole RestartTo call the functions you need to use the package name. A call to CloseConsole would look like this: Engine.CloseConsole() The Engine package also adds these objects
AActors FNames UObjectsTo access these objects you use . For example, you can get the 10th FName like this:
FNameThe Lua length operator works on these objects. For example:
print(#Engine.FNames) 40016The Lua length operator also works on objects. It will return the object's index into UObjects. For example:
X = Engine.UObjects print(#X) 123This allows you to check if two objects are the same. For example:
X = Engine.UObjects Y = Engine.UObjects print(X == Y) falseYou would think these objects would be the same, but they are not. They are two different Lua objects that point to two different C++ data structures. There is a pointer in the C++ data structure that points to the real object. These pointers are the same, but Lua knows nothing about them. If you print the objects from Lua you get:
print(X, Y) userdata: 1CAE4390 userdata: 1CAF19A8 They are not the same. If you print the objects lengths you get: print(#X, #Y) 123 123 print(#X == #Y) true
Engine.CloseConsole()This function closes the Lua console.
Engine.DumpThis command will dump whatever object you pass to it. It is very useful for figuring out what object you have, what properties it has, and what values the properties currently have. For example, assuming that PC contains an a player controller object:
Engine.Dump(PC.Region) Struct Actor.PointRegion part of [StudentController Entry.StudentController] FPointRegion AZoneInfo * Zone [ZoneInfo8] int iLeaf  byte ZoneNumber  Engine.Dump(PC.Pawn.Location) Struct Object.Vector part of [AGP_Character Entry.AGP_Character] FVector float X [-255.703] float Y [-8636.898] float Z [14.950]The dumps are sent to both the Lua console and the log file.
Engine.DumpClassThis command will dump the class information of whatever object you pass to it. It is very useful for figuring out an object's inheritance. For example, assuming that PC contains an a player controller object:
Engine.DumpClass(PC) Class AGP.Student Controller Class AGP.HumanController Class Engine.PlayerController Class Engine.Controller Class Engine.Actor Class Core.ObjectThe dumps are sent to both the Lua console and the log file.
Engine.FindFirst(FName, UClass) / FindNext(UObject)These commands are used to speed up searching the massive UObjects list. Internally, the game hashes all the objects by their FNames. It then links similar objects based on their hashes. The effect is that it is normally 4000 times faster to search the hash table instead of the full list. The only catch is that the objects you are interested in must have the same FNames.
FindFirst(FName, UClass) will return the first object in the hash list that matches FName and UClass, or nil if there are no objects.
FindFirst(UObject) will return the first object in the hash list that matches Object (FindFirst uses the FName and UClass of UObject).
FindNext(Object) will return the next object in the hash list, or nil if there are no more objects.
Here is an example on how to find all the PRIs:
FName_PRI = Engine.FNames['PlayerReplicationInfo'] UClass_PRI = Engine.UObjects['Class Engine.PlayerReplicationInfo'] PRI = Engine.FindFirst(FName_PRI, UClass_PRI); while PRI do print(PRI.PlayerName) PRI = Engine.FindNext(PRI) endHere is another way:
PRI = Engine.FindFirst(PC.PlayerReplicationInfo) while PRI do print(PRI.PlayerName) PRI = Engine.FindNext(PRI) end
Engine.FindFirstAActor(UClass) / FindNextAActor(UObject, UClass)These commands are used to speed up searching the large AActors list. It is much faster to search that list in C++ than in Lua.
FindFirst(UClass) will return the first object in AActors that IsA UClass or nil if there are no objects.
FindNext(Object, UClass) will return the next object in AActors that IsA UClass or nil if there are no more objects.
Here is an example on how to find all the pickups:
UClass_Pickup = Engine.UObjects['Class Engine.Pickup'] Pickup = Engine.FindFirstAActor(UClass_Pickup); while Pickup do print(Engine.FNames[Pickup.Name]) Pickup = Engine.FindNext(Pickup, UClass_Pickup) end
Engine.FullName(UObject)This command returns the full name of UObject. Here is an example that prints out all the AActors.
for i = 0, #Engine.AActors-1 do if Engine.AActors[i] then print(tostring(i)..' '..Engine.FullName(Engine.AActors[i])) else print(tostring(i)..' Empty') end end
Engine.IsA(UObject, UClass)This command returns whether UObject is a UClass. Here is an exmple:
UClass_PRI = Engine.UObjects['Class Engine.PlayerReplicationInfo'] print(Engine.IsA(PC, UClass_PRI)) false print(Engine.IsA(PC.PlayerReplicationInfo, UClass_PRI)) true
This command will load