Explaining where to find logs file and write them
On game launch, Cyber Engine Tweaks generates individual logs files in each mod folder, using their name. eg, <
>/mods/my_mod/my_mod.log
.
This file contains all notices, errors and logs generated by the mod.
You can write the log file using the spdlog functions.
You can use Tailblazer App to watch files in live with a GUI, or use the following command line in the Windows Command shell:
Cyber Engine Tweaks has a global log file located in <
>/scripting.log
.
This file contains all logs from the CET Console.
You can write the log file by using the print() function.
You can use Tailblazer App to watch files in live with a GUI, or use the following command line in the Windows Command shell:
Explaining how to create and run a custom mod
Explaining how to create and run a custom mod
This page will tell you how the CET mod folder structure works. To download a ready-to-go example project, check the wiki's github repo.
Cyber Engine Tweaks will be looking for mods inside its/mods/
folder, with each mod having it's own subfolder.
Create a new folder in the <
>/mods/
folder to get started, e.g. my_mod
(snake case recommended)
init.lua
fileCET will be looking for an init.lua
file inside your mod folder. This is the entry point of your mod, and gets executed when the game is launched.
Each mod only has read / write access to its own subfolder, so any extra files need to be placed in the same folder or a subfolder.
The init.lua
file is the only file that gets automatically loaded, thus should contain all your initialization code.
Start by printing simple info into the CET Console using the print() function. Then register a listener on the onInit event, and print something else.
Launch the game, and open the CET Console. You should see your printed text.
Learn more about Events here. It is an important concept to assimilate for your future mod.
For communication between mods, use the GetMod() function.
Tips: Press the "Reload All Mods" button on the CET Overlay after making changes to your mod files to see the effect in live.
To now actually create a complex mod, you'll want to interact with the game's system, modify and create instances of game classes and modify the game's code. For that, head to the Scripting API section
Additionally read up on the CET Functions, for information on how to create custom keybinds, Observer and Override game functions, spawn objects and more
Codes good practices, pitfalls and tips
You're probably used to coding like this:
In LUA, you can skim a few processing cycles by using the early return style:
You can gain a significant amount of performance this way, especially when doing this in a loop.
LUA throws an exception if it encounters nil
in unexpected places. The corresponding error will look like this:
Open the corresponding file, find the correct line, and check what is being accessed there. It will look like variable.property
, or perhaps something will be concatenated to a string ("something something text" .. variable
).
You can assign a default value to the property in question:
While that won't solve any other problems, it will at least make the error go away.
Who doesn't know the problem? You want to know if your string is A, B, or C, but not D — and LUA doesn't have a switch statement.
Fortunately, there is a built-in and performant way to
Lua internalizes strings. That means these two strings will share a single representation in memory:
The comparison between those two strings will be almost-instant.
Every single pass of the loop will create a memory representation of "This is the same object!" and then discard it again.
Takeaway:
If at all possible, define things outside the scope of loops!
Lua's regex implementation is very limited. There is a limitation for pipes. For example, the following example will actually iterate twice after creating internal string representations:
It is faster to just do this:
On top of that, string.match
will return the entire string if no match is found:
The alternative:
Takeaway:
Avoid regex
prefer String.find()
over String.match()
Don't do this (30% less performant):
Do this instead:
String concatenation and comparison can be the difference between a brief stutter and a complete freeze or even crash to desktop. This is not a joke — see for more detail.
This becomes a problem when comparing strings in a loop (see ):
For a performance analysis of different kinds of string concatenation, check .