Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Description about the configuration file.
The configuration file can be found in <game_directory>/red4ext/config.ini
.
If there is no configuration file present then the file is automatically generated, with the default values, when the game is started.
Even if the configuration file has ini
extension, in fact, it is a TOML
file See toml.io for more information.
An example of the configuration file.
Guide how to install RED4ext.
You need to make sure that is installed.
Download the latest zip (e.g. red4ext_x.y.z.zip
) file from .
Extract the content of the archive in the game's directory.
Launch the game.
(Optional) Check the log file in <game_directory>/red4ext/logs/red4ext.log
to make sure everything works.
is currently only a plugin manager for plugins that extends REDengine 4. It takes care of loading the plugins for the specified game's version.
is a library that can be used to extend REDengine 4. The library provide the following features:
Interacting with the game's scripting VM (e.g. calling functions or accessing class properties);
Creating new native classes or functions;
Reversed game's structures;
See
Name
Type
Default
Description
version
unsigned integer
0
The file's version.
logging
level
string
info
The global log level.
Accepted values:
off
trace
debug
info
warning
error
critical
flush_on
string
info
The minimum log level that will trigger the flush.
Accepted values:
trace
debug
info
warning
error
critical
max_files
integer
5
The maximum number of rotated log files.
Minimum value: 1
Note: A log file is rotated every time the game starts.
max_file_size
integer
10
The maximum size, in megabytes, of a log file.
Minimum value: 1
plugins
enabled
boolean
true
Enable / disable plugins system.
ignored
string[]
[]
The specified plugins are ignored and will not loaded.
dev
console
boolean
true
Enable / disable the external console (useful for development).
wait_for_debugger
boolean
false
Block the process until a debugger is attached.
Download the plugin.
(Optional) If the plugin does not provide a directory structure, create a directory with the plugin name in <game_directory>/red4ext/plugins
.
Copy the plugin files as following:
If you have created a directory at step 2, copy the files in the newly created directory.
If you did not create a directory, copy the files in <game_directory>/red4ext/plugins
.
(Optional) Start the game and verify <game_directory>/red4ext/logs/game.log
if the plugin is loaded correctly.
Where to find the documentation
You can browse Red4Ext via Rayshader's excellent web tool NativeDB, where all documentation will be gathered and kept up-to-date by volunteers.
If you want to get involved, check out the github repository or this thread on the REDmodding Discord.
When writing a RED4ext plugin in conjunction with a Redscript project, it can be useful to create class members in RED4ext, and access them through Redscript. A similar example in code form can be seen here.
Here we need to create a struct that inherits from RED4ext::IScriptable
(the class that all classes inherit from in Redscript). The header for this needs to be defined at the top-level, or in a namespace (outside any function):
A template is then used to create all the necessary CP2077 hooks for the class - the type we pass to the template function is the type we just created, and the argument is the name of our class as a string in Redscript. We'll also need to define GetNativeType()
that returns a reference to our CP2077 type. The name of customControllerClass
doesn't matter in this context, as it's pointing to our type in RED4ext.
Using the class & type we've created, we'll write two hooks (RegisterTypes
and PostRegisterTypes
) to register the type with CP2077 at the appropriate times. The first one that gets called sets the isNative
flag for the class, which will match the native
descriptor on the Redscript side, and registers the type to CP2077:
The next block will manually set the parent of our type to IScriptable
, to match the class.
To make all of this work, we then need to hook-in our callbacks, which we do with RED4ext::RTTIRegistrator::Add
in our main function:
On this side, the declaration is pretty simple, and similar to the headers from the decompiled scripts. Technically the extends IScriptable
is implied for all classes, and can be omitted here:
Like usual, you can define any non-native member variables and methods here, and use them in Redscript, but out of the box our class doesn't do anything yet. In the following pages, we'll define some functionality with custom native functions.
To give our class some functionality, we'll first need to create a function, which we'll name GetNumber
. The arguments that this function accepts on the RED4ext side are very specific and unrelated to the arguments it accepts in Redscript, and need to be particular types.
In the example above, the float
in the header's float* aOut
is the return type - it can also be a RTTI type like RED4ext::GameObject
, but it needs to be a pointer. If the function takes no arguments, you can use void* aOut
in the header instead.
This function takes Vector4
and Int32
as arguments on the Redscript side, and to get these values, we have to use RED4ext::GetParameter
and the stack frame that's passed into our function through RED4ext. We'll retrieve them in-order, passing the function each of our variables' references. Once we've read the last argument, we need to run aFrame->code++
to let the system know we're done reading the arguments.
From there, we can manipulate & mutate them however we like. At the end of it, we'll need to give *aOut
a value, being sure to use the pointer. If the function has a Void
return type, we can omit this line.
Once we have our function declared, we'll need to register it to the class we created on the last page, which will be done in the PostRegisterTypes
callback:
In the RED4ext::CClassFunction::Create
function, we pass the type we've created, the long & short names of the function as strings (how it'll be referenced in Redscript), and then a reference to the function itself.
Just like the class, we need to add the isNative
flag to the function. The arguments need to be registered to the function using the name of the type (like it is in Redscript), followed by the argument name. The return's type is set in the same way, using the name of the type as a String.
This header declaration will look similar to other Redscript class declarations, but with the native
keywords, and the function added without a body (depending on your Redscript version, the semicolon at the end might need to be omitted):
To use this in your project, you can add additional variables & methods to the class and build it out that way, or you can use it just like a normal function in a hook like this:
RED4ext provides a logger for every plugin through the SDK class. First time a message is logged RED4ext will create a log file with the plugin's name in <game_directory>/red4ext/logs
directory.
The logger settings, such as rotation, file size, etc., are based on the user's configuration file.
To create a new plugin you can use whatever build systen / toolchain you would like, as long as the output is compatible with x86-64 architecture and with __fastcall
calling convention.
Some examples you can use one of the following:
You can use one of the following project as a starter for your own plugin (all of the projects below are already configured for RED4ext plugin development):
After you decide what build systen or toolchain you would like to use make sure to add RED4ext.SDK to project's include paths. This dependency is necessary since it provides the API that RED4ext is using to load the plugin, as well as the game's structures that you might need.
Your mod should export few functions in order to be loaded correctly (see below which functions needs to be exported), to export a function from C/C++ you can use RED4ext's helpers, RED4EXT_C_EXPORT
(equivalent of extern "C" __declspec(dllexport)
) and RED4EXT_CALL
(equivalent of __fastcall
).
Good to know: You must place your plugin in <game_directory>/red4ext/plugins
or in a sub-directory (e.g. <game_directory>/red4ext/plugins/<your_plugin's_name>
).
If your plugin needs to load other dynamic libraries (DLLs) you can place them in the same folder where your plugin is located.
If you keep your MSVC environment up to date, it will update Visual C++ Redistributable on your system. Players may not be on the same, latest version of VC Redist. In such case, the game is likely to crash. Make sure to inform players to download the latest version when troubleshooting. You can redirect them to this link.
Specify the API version of the plugin.
Returns the support API version supported by your plugins.
To support the latest version, return RED4EXT_API_VERSION_LATEST
.
To support a specific version, return RED4EXT_API_VERSION_<VERSION>
, e.g. RED4EXT_API_VERSION_0
.
This function is used to fill your plugin information, like name, author, supported game version, etc..
RED4ext::PluginInfo* - The pointer to the structure that contains information about your plugin.
Do not do anything in this function yet (like creating a hook or allocating a trampoline).
Runtime version is the game's version that your plugins support, if your plugin has runtime set to 1.21
your plugin will be loaded only if the game's version is 1.21
, else it would not be loaded. It is recommended to set it to RED4EXT_RUNTIME_LATEST
to target the latest game's version that the SDK defined.
If you want to use RED4ext only as a loader and you do not care about game's version use RED4EXT_RUNTIME_INDEPENDENT
.
The entry-point of the plugin. This equivalent of DllMain
except that it is called after RED4ext make sure that your plugin is compatible with the game's version.
Here you can attach hooks and register RTTI types.
Memory allocators are not initialized yet. If you need to use RTTI system (call functions for example), see Custom game states to execute your code when RTTI system is ready.
RED4ext::PluginHandle - The unique identifier of the plugin.
RED4ext::EMainReason - The reason why the main is called.
RED4ext::Sdk* - The pointer to the SDK structure.
false
- if the plugin did not initialize properly.
true
- if the plugin initalized properly.
If the entry-point function returns false
following a Load
notification, it receives an Unload
notification and the plugin is unloaded immediately. However, if the Load
code throws an exception, the entry-point function will not receive the Unload
notification.
RED4ext offers the possibility to attach custom game states to the game. These can be used to initialize or do some things before or after the game system are available, such as scripting system.
Every state has the following functions:
Called immediately after the state is activated. This function is called once by the game, so be careful what you want to do here. A good example is to initalize some memory that is needed later.
The return value is not taken in consideration. It is recommended to always return true
for future proofing.
Called every frame. This function can contain more complex code.
false
- if the state did not finish executing.
true
- if the state finished executing.
If the game / custom state returns true
it will not be called next frame. For example:
InitializationState::OnUpdate
- returns false
CustomInitState::OnUpdate
- returns true
Next frame only InitializationState::OnUpdate
will be called. Same for the reverse.
The only exception from this rule is the RunningState
where only the returned value by the game's state is taken into consideration. For example:
RunningState::OnUpdate
- returns true
CustomRunningState::OnUpdate
- returns false
Then the frame, RunningState::OnExit
will be called.
Called when the state is ending. This function is called once by the game, so be careful what you want to do here.
The return value is not taken in consideration. It is recommended to always return true
for future proofing.
This guide will show you how you can write a plugin with beautiful code thanks to RedLib and RED4ext.SDK. If you haven't, you should learn the fundamentals of writing a plugin (see Creating a Plugin).
You must install RED4ext.SDK in your project like any other plugin (see ). You need to install . See the README to configure your CMake project.
Now you can change the entry-point of your plugin like this:
We are going to create a zoo, and name our mod... Zoo
. Now lets create a generic Animal
class:
Now lets add a Wolf
to our zoo:
If you tried to declare a class with only RED4ext.SDK so far, it sure looks better now with RedLib! Now compile your project and install your plugin in the game's directory:
<Cyberpunk 2077>\red4ext\plugins\Zoo\Zoo.dll
We also need to declare native types so we can use them in scripts:
Lets create our zoo somewhere when the game starts:
Install scripts in your game's directory:
<Cyberpunk 2077>\r6\scripts\Zoo\Zoo.reds
<Cyberpunk 2077>\r6\scripts\ZooTest.reds
Run the game, you should see some outputs in the Game Log when using CET.
Happy coding!
This guide will show you how you can quickly install a plugin in your game's folder after building it.
is command line interface tool to improve your experience as a scripting modder. It allows you to run commands from a terminal to quickly install your plugin in the game folder. It is also convenient to make an archive with your plugin, ready to release to users on Nexus Mods.
This tool is also compatible with Redscript. See if you are also writing scripts in addition to a RED4ext plugin.
This tool requires a red.config.json
file to be present in the root directory of your project. Basically, it should be in the same directory of your CMakeLists.txt
file.
You can find everything you need to install / configure red-cli through its README.
You can add a command in your CMakeLists.txt
file to execute red-cli
after building in Debug or in Release mode. We will use the function add_custom_command
of CMake to do this.
We can ask CMake to execute the command red-cli install
in Debug mode and the command red-cli pack
in Release mode:
Now, every time you compile your project in Debug mode, it will install the DLL plugin and the scripts in the game's folder. You're ready to run the game and test your mod.
When your project is ready, you can compile your project in Release mode, it will create an archive with your DLL plugin and a bundle of your scripts. You could extract the archive in your game's folder, and test it to make sure everything is in order prior to releasing it on Nexus Mods.
This is a simple introduction to RedLib and how it can make your life easier when writing plugin with . You should definitively go to the and read through the entire README to learn about all the features it provides.