Lua API Introduction ZeroBrane is no longer in development and therefore not recommended anymore for development with Lua in Pragma. Please use Visual Studio Code instead. Pragma uses the programming language Lua 5.1 (with LuaJIT) for its scripting engine. If you're new to Lua, the PIL is a good starting point. Any text editor suited for programming (Notepad++, Sublime, Visual Studio Code, etc.) can be used to write Lua scripts, however using the ZeroBrane IDE is highly recommended due to its powerful debugging capabilities specialized for Lua development (including step-by-step debugging, breakpoints, auto-completion, etc.). There are many ways to execute Lua code, but the easiest one is via console commands: lua_run / lua_run_cl : Executes the specified Lua code serverside / clientside (if the game state is available) lua_exec / lua_exec_cl : Executes the specified Lua file serverside / clientside (if the game state is available) Pragma has one Lua instance per game state. The game state is split into a serverside portion and a clientside portion. The client generally handles things like rendering and device inputs, while the server handles AI, game logic, etc. Some components (like physics) are simulated on both sides and may or may not be synchronized. The Pragma Filmmaker, for instance, is an entirely clientside Lua addon. The game states (along with the Lua instances) are initialized when you're loading a map / starting a game, which means Lua commands and scripts cannot be executed when you're still in the main menu. Which game states are available depends on the situation: Starting a local game/server: Both game states are initialized. Connecting to a server: Only the clientside game state is initialized. Starting a dedicated server: Only the serverside game state is initialized. These Lua instances are completely independent and cannot communicate directly with each other (except via net messages). Any variables or functions you define in the serverside state will not be accessible in the clientside state and vice versa. Here are a few examples using the lua_run and lua_run_cl console commands: lua_run var = "This is a serverside variable" -- Defines the global serverside variable 'var' lua_run_cl print(var) -- Prints 'nil' (indicating an undefined variable) to the console, because 'var' was not defined clientside lua_run print(var) -- Prints 'This is a serverside variable' to the console, because we're back in the serverside instance You can also place Lua-files in one of the following autorun directories, in which case they will automatically be executed when the game is started: "lua/autorun/.lua": The Lua-file will be executed for both the serverside and clientside Lua instances. "lua/autorun/server/.lua": The Lua-file will be executed serverside. "lua/autorun/client/.lua": The Lua-file will be executed clientside. API Documentation You can find a list of all available Lua classes, libraries and functions in the API documentation. Some functions are only available serverside, some only clientside, which is indicated by the colored bars in front of the function names in the navigation: Anything with a blue bar is available serverside, and anything with a purple bar clientside. For instance, the client cannot trigger a map change, so game.change_map() can only be executed via the serverside Lua instance. If you want to know how a particular function is implemented, you can click the -logo, which will direct you to the function implementation on the Pragma GitHub repository. If you have configured ZeroBrane, all of the functions should also appear in the auto-complete list when typing the name of a library or class: In-Engine Documentation In addition to the online API documentation, you can also use the lua_help console command to retrieve the information for a function/library/class ingame: Lua errors will also use this documentation to provide you with suggestions on how to correct the error: Hello World Creating a Lua script is very straight forward. Simply create a new text-file and add the following line: print("Hello World") Then save that file as "hello_world.lua" to "Pragma/lua/". To execute the script, simply start a new game and run the console command lua_exec_cl hello_world.lua and you should see the message "Hello World" printed in the console. Any Lua files that have been executed at least once are cached by the Engine and automatically reloaded when changed in the future (until you close the game). This means if you make any changes to the file, all you have to do is save it, and it will automatically be executed again (i.e. you don't have to run lua_exec_cl anymore). You can test this by changing the print message in your Lua-script and then saving it, and it should automatically print your new message to the console. Addons In general, putting Lua scripts in the main Lua directory ("Pragma/lua/") should be avoided to avoid clutter and naming conflicts and an addon should be used instead: Create a new directory called "hello_world" in "Pragma/addons/" Create a new "lua" directory inside it Move your "hello_world.lua" to "Pragma/addons/hello_world/lua/hello_world.lua" Pragma will automatically mount the addon, and will treat all asset files within the addon as if they were in the main Pragma directory. This means that despite the file being in a different location, you can still use lua_exec_cl hello_world.lua to execute the file. Examples Creating a timer Lua state: Any -- Print "Hello" every 2 seconds local numberOfRepetitions = -1 -- -1 = infinite local timer = time.create_timer(2.0,numberOfRepetitions,function() print("Current game time:",time.cur_time()) end) timer:Start() -- Remove the timer after 15 seconds using a second timer time.create_simple_timer(15,function() util.remove(timer) end) Registering a custom console command Lua state: Any console.register_command("custom_command",function(pl,...) if(pl ~= nil) then print("Command was initiated by player ",pl:GetEntity():GetName()) end print("Command arguments: ",...) local arg1,arg2,arg3 = ... -- Do something with arguments end) Creating a GUI element Lua state: Client local rect = gui.create("WIRect") rect:SetColor(Color.Red) rect:SetPos(Vector(32,32)) rect:SetSize(256,65) local text = gui.create("WIText",rect) text:SetColor(Color(0,255,64,255)) text:SetPos(5,5) text:SetText("Hello World") text:SizeToContents() Classes and class inheritance Lua state: Any -- Define class 'Car' in 'util' library util.register_class("util.Car") -- The constructor for the 'Car' class, which allows us to create an instance of the class like so: -- local carInstance = util.Car("Name of the car") function util.Car:__init(name) self.m_name = name self.m_color = Color.Red end function util.Car:SetName(name) self.m_name = name end function util.Car:GetName() return self.m_name end function util.Car:SetColor(color) self.m_color = color self:OnColorChanged(color) end function util.Car:GetColor() return self.m_color end -- These can be overwritten by derived classes function util.Car:GetWheelCount() return 4 end function util.Car:OnColorChanged(newColor) print("Color of car '" .. self:GetName() .. "' has been changed to " .. tostring(newColor) .. "!") end ------- -- Define class 'Truck' and derive from base class 'Car' util.register_class("util.Truck",util.Car) function util.Truck:__init(name) util.Car.__init(self,name) -- Base constructor has to be called, note the use of '.' instead of ':' for calling base functions end function util.Truck:GetWheelCount() return 6 end -- Overwrites the base function when called on a truck instance function util.Truck:OnColorChanged(color) util.Car.OnColorChanged(self,color) -- Call base function debug.beep() -- Play a beep sound after the message has been printed end ------- -- Create car object local car = util.Car("Car Name") car:SetColor(Color.Lime) print("Number of car wheels: " .. car:GetWheelCount()) -- Create truck object local truck = util.Truck("Truck Name") truck:SetColor(Color(0,255,128,255)) print("Number of truck wheels: " .. truck:GetWheelCount()) Respawn all players Lua state: Server for ent in ents.iterator({ents.IteratorFilterComponent(ents.COMPONENT_PLAYER)}) do local playerC = ent:GetComponent(ents.COMPONENT_PLAYER) playerC:Respawn() end Pragma Filmmaker The Pragma Filmmaker is implemented as a Pragma addon written in Lua, you can find the source code on GitHub: https://github.com/Silverlan/pfmVisual Studio Code You can use any script editor of your choice to create Lua scripts for Pragma. The information on the page is the recommended approach, but it is not required. Pragma supports Lua development and debugging with Visual Studio Code. This includes code auto-completion and suggestions: as well as debugging using breakpoints, step-by-step code execution and immediate code execution: Setup To enable it, install these extensions: Lua by sumneko: Lua Debug by actboy168: extensionPath by actboy168: Optional: GitHub Copilot StyLua For automated code-formatting, install the following extension: StyLua by JohnnyMorganz: After installing StyLua, press Ctrl +LShift +P, and run the command "Preferences: Open User Settings (JSON)". In the JSON file, add the following line below editor.defaultFormatter: "editor.formatOnSave": true Once all of these extensions are installed, open the root directory of Pragma in Visual Studio Code. Debugging To be able to use the Lua debugger, you have to start the debugger server in Pragma first. LuaJIT will be disabled when debugging, which means script execution will be slower. Add -console -luaext to the launch options of Pragma. This will enable additional Lua libraries required by the debugger, as well as the developer console, which will print Lua errors and can be used to execute Lua code directly. Open the main Pragma directory in Visual Studio Code (File > Open Folder...). Run the console command debug_start_lua_debugger_server_cl in Pragma to launch the debugger server. Press F5 in Visual Studio Code to start debugging. You can now use the debugging tools in Visual Studio Code. Breakpoints Conditions Immediate Code Execution ZeroBrane IDE Overview All you need to create Lua-scripts for Pragma is a basic text-editor, however to get access to advanced debugging capabilities, it's recommended to use the ZeroBrane Studio Lua IDE. ZeroBrane is free and allows you to debug Lua code with features like step-by-step code execution and breakpoints, which you can see in action here: Pragma also ships with an auto-complete script for ZeroBrane to maximize productivity: You are of course free to use any other editor, in which case you can ignore the rest of this tutorial. Setup After downloading and installing ZeroBrane, a few more manual steps are required to set it up for Pragma: Start ZeroBrane, Select "Project -> Project Directory -> Choose..." from the menu bar, navigate to your Pragma installation (Default: "C:/Program Files (x86)/Steam/steamapps/common/Pragma/") and select it. Without this step, the debugger may not be able to locate the Lua files during debugging. Navigate to "Pragma/doc/ZeroBrane" and copy its contents to your ZeroBrane installation (Default: "C:/Program Files (x86)/ZeroBraneStudio"). Select "Edit -> Preferences -> System" from the menu bar and append the following lines to the end of the file: include "pragma.lua" editor.autotabs = true Save the file and restart ZeroBrane. Select "Project -> Lua Interpreter -> Pragma" from the menu bar. This step is required for the auto-complete feature. This completes the basic setup for ZeroBrane, however to use the debugging capabilities a few more steps are required every time you want to use the debugger. The debugger requires that you add -luaext to the launch parameters in Pragma: If set up correctly, you should see a red "[D]" next to the version number in the main menu: This will enable several Lua modules which are required for the debugger. These modules could potentially be used to cause damage to your system by a malicious Lua-script, so it's recommended to remove the launch option again when playing on multiplayer servers, or if you've downloaded custom addons from sources you don't completely trust. The following steps have to be executed every time you want to use the debugger, after Pragma has been started, but before a map has been loaded (i.e. while you're in the main menu, or before you've run the "map" command on a dedicated server). Start ZeroBrane and select "Project -> Start Debugger Server" from the menu bar. Run the console command sh_lua_remote_debugging 1 if you want to debug a serverside script, or sh_lua_remote_debugging 2 if you want to debug a clientside script. Open a Lua-file from your Pragma installation in ZeroBrane. Any Lua-file will do, but without this step, ZeroBrane may not be able to locate any Lua-files at all. Load a map. The "output" window of ZeroBrane should say something along the lines of "debugging session started", which means it connected successfully to Pragma. In this case Pragma should appear frozen and unresponsive in the background and you should see the following controls in the menu bar of ZeroBrane: Click the green arrow (alternatively press F5) to resume Pragma. The debugger is now fully set up and initialized. You can find an overview of its features and how to use them here. API Documentation Lua API documentation of all available classes, libraries and functions.