Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
On onInit gets triggered once, when CET loads in all the mods. This event ensures that CET has fully loaded, and you have access to the Scripting API. There can be only one onInit event per mod.
Use it to register any Observers, as well as do any one-off actions needed for your mod.
This event is a safe starting point for your code interaction with the game, as it guarantees the access to most of the Scripting API.
This event is also triggered when using "Reload all mods" button in the CET Overlay, as it fires when CET load all mods.
An overview of CET-Exclusive functions
This event works similarly to , except that it is used for drawing custom ImGui UI. It gets triggered on every frame that the game runs, thus is framerate dependent.
Use this event with caution, as it is triggered continuously once the game is launched.
Trying to draw ImGui UI outside this callback is prohibited
This event gets triggered on every frame that the game runs, thus is framerate dependent. The callback function gets the deltaTime
passed along with it, which measures the frametime in ms, useful for making e.g. timers.
In here you can put any code that you want to run every frame, although it is best practice to only run your code when needed, e.g. using .
Use this event with caution, as it is triggered continuously once the game is launched.
Cyber Engine Tweaks has builtin events which can be listened using the registerForEvent()
function. These listeners must be registered inside the init.lua
file.
Keep in mind that CET events are not game events. For example, doesn't mean the game the initializing, but rather that CET loaded mods and the game's Scripting API.
If you need to listen for game events, take a look at the functions.
Here is a video showing when events are triggered in real-time:
This example use . Check the for further information on its usage.
This event gets triggered even before onInit, and can be useful for making changes to the TweakDB, as some values can only be changes very early during the loading process.
This event get triggered when the CET Overlay gets shown.
Use this to keep track of the overlays state, and e.g. to only draw your own UI when CETs overlay is visible. Use it in conjunction with onOverlayClose to get a proper on/off switch case.
This example use the onDraw event, which is triggered continuously. Make sure to check the documentation before any modification.
This event get triggered when the CET Overlay gets hidden.
Use this to keep track of the overlays state, and e.g. to only draw your own UI when CETs overlay is visible. Use it in conjunction with onOverlayOpen to get a proper on/off switch case.
This example use the onDraw event, which is triggered continuously. Make sure to check the documentation before any modification.
Cyber Engine Tweaks allow mods to register hotkeys that can be assigned by the player in the CET Binding screen, and execute custom code once pressed. There are two kinds of hotkeys:
Hotkeys and Inputs, while having similar functionalities, are displayed in two separated groups.
Remember to register Hotkeys/Inputs at root level, outside of any event.
Hotkeys & Inputs are displayed in the CET Bindings screen sorted in the order they were registered in the code. If you want to sort hotkeys by label in ascending order for example, you'll have to change the registration code order accordingly.
Hotkeys & Inputs can be triggered by the user from anywhere, at anytime, as soon as CET loaded your mod (even earlier than onInit event).
Which means the user might press your hotkey in the Main Game Menu or in Settings Menu. You have to keep that in mind when working with hotkeys, and make sure your script is executed where it is supposed to.
Hotkeys & Inputs are triggered on top of the game's keybinds. Which means it's possible that player set a hotkey on "R".
In-game, when the player use "R" to trigger your script, it will also trigger the game's Reload function.
Inputs are buttons events that handle both key press and release states. They must be registered using registerInput()
at root level, outside of any event, in the init.lua
file.
The button state (press/release) is defined in the first argument passed to the callback.
You can register an Input and make it behave like a Hotkey. This method is more reactive as it triggers on key press, when a Hotkey is triggered on release.
It is important to check the keypress
argument inside the callback. Otherwise the code will be executed twice:
One time when the key is pressed
A second time when released
Returns the width and height (respectively) of the game window in pixels.
Returns the return value of the mod with the given name.
If you don't return anything in your init.lua
file, this function will return nil
. This will often look like return MyMod:new()
at the end of your file. See the for info about how classes can be implemented in Lua.
Returns the singleton for the given type name if it exists, otherwisenil
.
A singleton is the sole instance of a type, often used for global operations.
Returns the current CET build's commit hash.
Returns whether the specified .archive
file is present in the archive/pc/mod
folder
This technique can be used to detect whether your Redscript mod is present, from CET side. It can be useful if you are writing a mod with both languages for some reason.
You can declare a static method without a body. It will do nothing:
You can now test whether this method is defined from CET side using this:
You can call IsRedscriptDetected()
and it will return true
when your Redscript method is detected (meaning your Redscript mod is loaded) or false otherwise.
Don't forget to change NameOfYourMod
in both cases.
Hotkeys are buttons events triggered on key release. They must be registered using registerHotkey()
at root level, outside of any event, in the init.lua
file.
are not triggered while the player stay pressed on a game's keybind.
For example, if the player move forward with "W" and press a Hotkey at the same time, it won't be triggered.
For this reason, it is recommended to use instead, as they are always triggered.
Prints one or more objects to the and file. Multiple objects will be printed separated by a space.
Write a string in the file, eg, <
>/mods/my_mod/my_mod.log
.
There are several spdlog
methods, all are identical and have the same output:
spdlog.debug()
spdlog.trace()
spdlog.info()
spdlog.warning()
spdlog.error()
spdlog.critical()
It is recommended to use spdlog.info(tostring(my_var))
to make sure the variable is compatible, as boolean
, interger
and other types will throw an error.
Returns a JSON-ish string with details about the members of obj
:
Type name
Instance functions
Static functions
Properties
The listed functions include their signatures.
If detailed
is true, function descriptions will include the function's full name hash, short name, and short name hash.
Returns the game's internal debug string for the given object. This string displays the object's properties and their values.
This example use the event, which is triggered continuously. Make sure to before any modification.
obj
must be an instance of a wrapped game type, such as PlayerPuppet
which is returned by Game.GetPlayer()
. will dump the names of all such types.
Beware that this string probably won't have any line breaks, so it's more advisable to open <
>/scripting.log
in a text editor with line wrapping to view the output of this function.
Like , but takes a type name rather than an object instance. Use to get a list of all types.
Dump all type names to <
>/cyber_engine_tweaks.log
and prints to the the number of types dumped.
Helper functions which let you construct internal data types.
string
) -> GameType
Create a new object of the type given by typeName
. This type should be an internal game type.
The geometric types discussed below can also be created with NewObject.
table<x: float, y: float, z: float>
) -> Vector3
Create a new Vector3
from a table of x
, y
, and z
floats.
Property
Description
x: float
The x-axis component of the vector
y: float
The y-axis component of the vector
z: float
The z-axis component of the vector
In Cyberpunk, the Z axis is the up axis.
table<x: float, y: float, z: float, w: float>
) -> Vector4
Create a new Vector4
from a table of x
, y
, z
, and w
floats.
Property
Description
x: float
The x-axis component of the vector
y: float
The y-axis component of the vector
z: float
The z-axis component of the vector
w: float
The w-axis component of the vector
You may notice that functions like PlayerPuppet:GetWorldPosition
will return a Vector4
, even though, intuitively, 3D coordinates only include x, y, and z values. These Vector4
values are known as homogenous coordinates in graphical programming, useful in matrix transformations.
All you really need to know is that the 4th value, w
, should always be 1 when you are dealing with 3D coordinates.
table<roll: float, pitch: float, yaw: float>
) -> EulerAngles
Create a new EulerAngles
from a table of roll
, pitch
, and yaw
. Angle values are in degrees.
Property
Description
yaw: float
The horizontal angle in degrees along the axis pointing up.
0 is north, 90 is west, 180 and -180 are south, and -90 is east.
pitch: float
The vertical angle in degrees along the axis pointing to the right.
-90 is down, 0 is straight ahead, and 90 is up.
roll: float
The roll angle in degrees along the axis pointing forward.
Positive values rotate anti-clockwise and negative values rotate clockwise.
table<i: float, j: float, k: float, r: float>
) -> Quaternion
Create a new Quaternion
from a table of a vector part i
, j
, k
, and a scalar (real) part r
.
Property
Description
i: float
The x-axis component of the quaternion
j: float
The y-axis component of the quaternion
k: float
The z-axis component of the quaternion
r: float
The scalar (real) part of the quaternion
Quaternions are also often expressed with w, x, y, z
terms, which map to our terms as following:
w == r
x == i
y == j
z == k
table<hash_hi: uint32, hash_lo: uint32>
) -> CName
Create a new CName
from a table of hash_hi
and hash_lo
.
Property
Description
hash_hi: uint32
The higher 32 bits of the CName
's 64-bit hash
hash_lo: uint32
The lower 32 bits of the CName
's 64-bit hash
value: string
The text value of the CName
table<hash: uint32, length: uint8>
) -> TweakDBID
Create a new TweakDBID
from a table of hash
and length
.
Property
Description
hash: uint32
The CRC32 hash of the item name
length: uint8
The length of the item name
table<id: TweakDBID, rng_seed: uint32, unknown: uint16, maybe_type: uint8>
) -> ItemID
Create an ItemID
from a table of id
, rng_seed
, an unknown field unknown
, and an unknown field maybe_type
.
Property
Description
id: TweakDBID
The TweakDBID referenced by this ItemID
tdbid: TweakDBID
Alias for id
rng_seed: uint32
The RNG (random number generation) seed used for loot generation
unknown: uint16
Unknown field
maybe_type: uint8
Unknown field, possibly a type
NewProxy is a built-in CET feature you can use to declare callback functions. You can use it to bind a Lua function as a callback with game's script system.
You can now generate NewProxy using NativeDB. You need to configure option Clipboard syntax to Lua. You can click on the "copy" button of a function, pick Copy NewProxy and it will copy the code in your clipboard. It only works for classes with their names ending with Listener.
CallbackName is an arbitrary name you define. A callback name can be formatted as follow On[Action]
(e.g. OnDamaged
or also OnPlayerDamaged
).
CallbackDefinition is the signature of the script function (args) and the Lua function (callback) you want to be executed when the callback is triggered.
The list of arguments must indicate the name of the types to expect. For example with a callback function which receives a String
, an Int32
and a reference to a GameObject
, it should be defined like this:
In this case, you can define your function callback like this:
The signature of the function depends on the game's script function you want to register a callback for.
You can use NativeDB to know the types of arguments to declare. By default, the syntax will be written in Redscript. You can change the option Code syntax
in the settings and select Pseudocode · Legacy
instead. Basically, it will show you handle:GameObject
instead of ref<GameObject>
(among other things).
Lets create a proxy:
After creating the proxy, you can use it to pass the target and function you want to callback. Lets say a game's script is defined as:
We can call the function RegisterHit
to register our callback with our proxy like this:
Note that the value, when calling listener:Function("OnHit")
, is the same we declared in the proxy.
This way, you can create multiple callback in a proxy and you just need to call listener:Function
with the name of the callback you want to use. For example:
This example will be using Codeware and its system to listen for game events. It will listen for the event Session/Ready
and print a message in CET logs.
It is generally advisable to useObserve
whenever possible, and only use Override
when absolutely necessary
Override is a built-in CET function allowing developers to rewrite a game's class method. It must be registered using the Override()
function inside the onInit event, in the init.lua
file.
The provided callback
is always filled as follows:
The first argument is the current object that execute the method. This argument is not present when function/method is static.
Others arguments passed to the targeted method, if any.
The last argument is the original callable method.
You can now generate Override using NativeDB. You need to configure option Clipboard syntax to Lua. You can click on the "copy" button of a function, pick Copy Override and it will copy the code in your clipboard.
Considering the following class and method:
When applying Override()
, the callback would be filled with the following arguments:
The self
and wrappedMethod
parameters can be renamed at your convenience:
_
this
class
method
whatever
The last argument of the Override()
function, wrappedMethod
, contains the original method as a callable function. We can use it to execute the original code and/or retrieve its result (if it returns something).
It is highly recommended to know the overriden method return statement to avoid breaking the script, and use wrappedMethod
accordingly.
Any method declared void doesn't return a value. Overriding it follow the same logic:
The same logic is applied to methods with a specific return statement. Overriding it must return a compatible type:
It is not required to execute the original code using wrappedMethod
. This can be omitted, but it exposes the script to malfunctions if not handled properly.
Do not allow the player to crouch:
Do not allow the player to crouch if in ADS:
Methods for interacting with TweakDB, the game's internal data store.
TweakDB is like the game’s database for gameplay features. It’s not actually code itself, but very large amounts of data structures, many of which link together, to make coherent gameplay elements.
TweakDB has two main elements: Flats, and Records Flats are just like a single piece of data, like a number, a string, a pointer to a record, etc. Records are like a collection of flats. Records have possible types, like a character record or a clothing record. The type of record determines what set of flats the record has.
An example of these gameplay features nearly entirely contained in TweakDB, would be the damaging quickhacks like Overheat, Contagion, and Short Circuit. The quickhack item to unlock them is in tweakdb, as well as the process of unlocking, making them show up on enemies, the uploading process, the status effect applied, all the special effects possible, as well as the stats to customize all of these things. Almost anything about these quickhacks can be changed in TweakDB.
To transform a TweakDBID into a gameItemID, call ItemId.FromTDBID(tbdID)
Print info about the TweakDB. Displays the number of flats, records, and queries, the size in bytes of flatDataBuffer, and the number of created records.
GameItemIdTo get a TweakDBId's human-readable record name rather than its hash, use id.value
!
Get a TweakDB record by name or ID.
Get a table of all TweakDB records under a given type.
Get a TweakDB query by name or ID. Returns a table of TweakDBIDs.
Get a TweakDB flat by name or ID.
Set a TweakDB flat by name or ID and update it. Returns whether the flat was successfully set.
Set a TweakDB flat by name or ID without updating it. Returns whether the flat was successfully set.
Update (flush data of) a TweakDB record by name, ID, or handle. Returns whether the update was successful.
Create a new TweakDB record. Returns whether the record was created successfully.
Clone an existing record identified by clonedRecordName
or clonedRecordID
to a new record named recordName
or with a TweakDBID
of recordID
. Returns whether the record was cloned successfully. If a record named recordName
or with ID recordID
already exists, this method will fail.
Delete an existing TweakDB record. Returns whether the record was deleted successfully.
Movement and camera-related functions
Opposing to onInit, this event gets triggered whenever CET unloads all the mods, either due to the game shutting down, or when pressing the "Reload all mods" button in the CET Overlay.
Use this to do any clean-up work for your mod, e.g. despawning objects or removing status effects.
Observers are builtin CET functions that allow developers to detect when a function/method is executed by the game. They must be registered inside the onInit event, in the init.lua
file.
There are two kinds observers:
ObserveBefore()
which is triggered right at the moment the function/method is called
ObserveAfter()
which is triggered once the game finished to execute the function/method
The provided callback
is always filled as follow:
The first argument is the current object that execute the function/method. This argument is not present when function/method is static.
Others arguments passed to the targeted function/method, if any.
You can now generate Observable and ObservableAfter using NativeDB. You need to configure option Clipboard syntax to Lua. You can click on the "copy" button of a function, pick Copy Observable or Copy ObservableAfter and it will copy the code in your clipboard.
Observe()
is an alias of ObserveBefore()
. They both work the same.
Here is a visual representation showing where observers are executed in the game's script:
In this representation, the observer callback would be filled with the following arguments:
The self
parameter can be renamed at your convenience:
_
this
class
whatever
In the code above, the observer listens to AimingStateEvents:OnEnter()
, which is triggered everytime the player enters in ADS state.
Additionally, the OnEnter()
method is responsible to apply different effects, like the camera zoom, the initial stamina drain etc... Following this logic, this means:
Using ObserveBefore()
allows to hook in before these effects are applied
Using ObserveAfter()
guarantees the method finished to apply all the effects
⚠️ All examples in this Observe/Override method
ShootEvents.OnEnter
to gain access tostateContext
.
AdjustTransform
Base class for AdjustTransformWithDurations
. Seems to do nothing if passed to adjustTransform
scriptable parameter. Do not use: your movement will be blocked indefinitely until you reset adjustTransform
.
AdjustTransformWithDurations
Discovered by void*
Request to change player trajectory (view angles) and/or player position.
This code has to be executed in the context where you have access to StateContext for example: https://nativedb.red4ext.com/ShootEvents#OnEnter
Function has 3 types of behavior: set trajectory, set position or set both.
This code will smoothly point your camera towards {0, 0, 0}
.
GameObject
for trajectory
Does not change player's pitch.
Seems to target "nearest" targeting component (aka hitbox).
SetRotation
is ignored if target is set.Will freeze player in place/in air while it's aiming (same behavior as
LookAt
)
This function seem to use TargetingSystem to find the "best component" and then calls a LookAt
.
(Look at this function and this one)
Cyber Engine Tweaks allow mods to listen or overwrite game's script functions/methods. There are three kinds of functions:
Observe allows to listen for function/method execution
Override allows to overwrite a function/method
NewProxy allows to trigger a function/method callback using game's script system
Miscellaneous functions useful for debugging and getting special objects and info.