Lua CLI Utility for Dual Universe
npm install @wolfe-labs/du-luacrequire statements. It follows the following naming format: Package:File, though you should also be able to directly access a file in your current project by just pointing to the file instead. The .lua extension is not required. In cases where you try using require with an not found file, you will receive a small warning on your console but it won't fail the build, thus allowing to allow the game's built-in libraries, such as dkjson.
du-lua add-code-completion
---@type ElementClassName after its declaration, replacing ElementClassName with the desired element class:
lua
local myCoreUnit = myCoreUnit ---@type CoreUnit
`
$3
DU-LuaC has built-in support for multiple event handlers, which makes it easier to write modular scripts as you never override another script's event handler. They are automatically added to any liked component which has in-game events.
In case you want to add event support for your own objects and instances, use the library.addEventHandlers(yourInstance) function, which will add three new functions to your object:
| Signature | Description |
| --- | --- |
| handlerId = obj:onEvent(event, handler, ref) | Calls handler whenever obj emits an event of type event, optionally replacing the value of self with ref and optionally saving the handler ID in handlerId |
| obj:clearEvent(event, handlerId) | Clears the handle with identifier handlerId from the event of type event on obj |
| obj:triggerEvent(event, arg1, arg2, ...) | Triggers the event of type event on obj, passing all following arguments (such as arg1 and arg2) |
Please note that the first argument when calling handler will always be the either the instance itself or the value defined in ref, so for example, the mouseDown event for a Screen Unit is triggered as screen:triggerEvent('mouseDown', x, y), but the event handler will have the following signature: onScreenMouseDown(screen, x, y), the same also works for internals such as timers with onTick(unit, timer), etc. If you want to pass down your own self to be used inside handler, you must pass it as the ref argument to :onEvent
$3
Allows you to get lists of elements linked on your Control Unit, optionally filtering them by element class and name!
Below you have a list of functions and how to use them:
| Signature | Description | Sample |
| --- | --- | --- |
| library.getCoreUnit() | Returns the connection to the Core Unit, if it's connected | local core = library.getCoreUnit() |
| library.getLinks(filter, noLinkNames) | Gets a list of linked elements, optionally filtering based on the element's function stated in filter (you can supply nil to ignore filtering). When noLinkNames is true, you get indexes instead of link names as the keys | local screens = library.getLinks({ getClass: 'ScreenUnit' }) |
| library.getLinksByClass(elementClass, noLinkNames) | Gets a list of linked elements matching the selected class. When noLinkNames is true, you get indexes instead of link names as the keys | local screens = library.getLinksByClass('ScreenUnit') |
| library.getLinkByClass(elementClass) | Same as the previous function, but returns the first matching element | local screen = library.getLinkByClass('ScreenUnit') |
| library.getLinkByName(elementName) | Gets an element's link based on the element name (not the link name!) | local screen = library.getLinkByName('Main Screen') |
Please note that: to be able to get elements by their name, you will need to link your Core Unit to your Control Unit, thus losing one link. In case you don't want to go that route, you can still hard link your slot via the CLI. The disavantage of this is that you will have to remember the linking order for these elements.
$3
With the library.embedFile(file) function you are able to embed files at compilation time.
A great use case for HTML templates or any other kind of "large" content. You can simply put everything into a file (let's call it "hud.html"), edit it with your favorite editor's full capability of syntax highlighting and, when done, simply embed it into your code automatically with local hud = library.embedFile('hud.html'). All the contents of your file will be output into as a string into the hud variable, as if it was always there!
Please note that:
- Values passed to that kind of function MUST be literals, so you can't pass any kind of value which requires processing (like 'test' .. 123, it must be pre-set as 'test123' instead).
- File paths are relative to the Lua file being currently processed
- File access is restricted only to the current project, due to security concerns
$3
In some larger-scale projects, you might want to be able to enable or disable things depending in a series of factors, such as your current build target or something specific to your build environment. With that in mind, the CLI has some basic support for compiler variables and directives.
Note: due to the way directives are currently implemented, nesting of directives is not possible.
#### Compiler Variables
Compiler variables are defined in each of your project's build targets, inside the variables property. You can add as many variables you want, the only limitation is that only strings, numbers and booleans are supported.
You can also override existing build target variables via the command-line, by adding options prefixed with --var:.
For example, let's say you have a "debug" variable set somewhere and you want to force it to false in every build target, you can append the following to the build command and it should do the trick: --var:debug=false
#### Conditional Directives (if/else)
There's currently some basic support for conditional directives, you can use them as follows:
`lua
---@if variable_name compared_value
system.print('something')
---@else
system.print('something else')
---@end
`
Note: For string values, your value must be surrounded by double quotes to be properly parsed.
You can also not include a value for comparison, in those cases, it will check if the value is either true or something not-falsey (not null, undefined, etc).
Post-Mercury (0.30) Support
As of the Mercury (0.30) update, all events now start with the prefix on. So, for example, the old update event is now onUpdate.
To keep transitions like this as easy as possible, the CLI has been versioned, with the Project Format v2 being introduced.
Projects created with the new format should always use :onEvent('onEventName'), with the on prefix, while projects created previous to that may still use the old format (:onEvent('eventName')) and the CLI should automatically translate any calls.
Please keep in mind that events that changed name (such as Laser Detectors now using onHit) will need to have their names renamed on code too. You don't need to prefix it with on though, just use :onEvent('hit') and it will be fine.
$3
To upgrade your project to v2, make sure you have fixed all your event handlers to the new format, then add the following JSON to the top of your project.json file, right before "name":
`
"cli": {
"fmtVersion": 2
},
`
It should look like this:
`
{
"cli": {
"fmtVersion": 2
},
"name": "your-project-name",
``