# Home

## What is this?

RED4ext is a script extender for Cyberpunk 2077, allowing modders to interact or extend the scripting system.

## Getting started

{% content-ref url="/pages/yuQ8l5yPboTG1vlBq9KS" %}
[Installing RED4ext](/getting-started/installing-red4ext)
{% endcontent-ref %}

{% content-ref url="/pages/-MjycK4JaWIuvGQsqhz4" %}
[Configuration](/getting-started/configuration)
{% endcontent-ref %}


# Installing RED4ext

Guide how to install RED4ext.

{% hint style="info" %}
You need to make sure that [Visual C++ Redistributable 2022](https://aka.ms/vs/17/release/vc_redist.x64.exe) is installed.
{% endhint %}

1. **Download** the latest zip (e.g. `red4ext_x.y.z.zip`) file from [GitHub](https://github.com/WopsS/RED4ext/releases/latest).
2. **Extract** the content of the archive in the game's directory.
3. **Launch** the game.
4. (**Optional**) Check the log file in `<game_directory>/red4ext/logs/red4ext.log` to make sure everything works.


# Installing a Plugin

* **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.


# Configuration

Description about the configuration file.

The configuration file can be found in `<game_directory>/red4ext/config.ini`.

{% hint style="info" %}
If there is no configuration file present then the file is automatically generated, with the default values, when the game is started.
{% endhint %}

{% hint style="info" %}
Even if the configuration file has `ini` extension, in fact, it is a `TOML` file See [toml.io](https://toml.io/) for more information.
{% endhint %}

## Options

<table data-header-hidden><thead><tr><th width="224">Name</th><th width="126">Type</th><th width="97">Default</th><th>Description</th></tr></thead><tbody><tr><td>Name</td><td>Type</td><td>Default</td><td>Description</td></tr><tr><td><code>version</code></td><td><code>unsigned integer</code></td><td><code>0</code></td><td>The file's version.</td></tr><tr><td></td><td></td><td></td><td></td></tr><tr><td><strong>logging</strong></td><td></td><td></td><td></td></tr><tr><td><code>level</code></td><td><code>string</code></td><td><code>info</code></td><td><p>The global log level.</p><p></p><p><strong>Accepted values</strong>:</p><ul><li>off</li><li>trace</li><li>debug</li><li>info</li><li>warning</li><li>error</li><li>critical</li></ul></td></tr><tr><td><code>flush_on</code></td><td><code>string</code></td><td><code>info</code></td><td><p>The minimum log level that will trigger the flush.</p><p><br><strong>Accepted values</strong>:</p><ul><li>trace</li><li>debug</li><li>info</li><li>warning</li><li>error</li><li>critical</li></ul></td></tr><tr><td><code>max_files</code></td><td><code>integer</code></td><td><code>5</code></td><td><p>The maximum number of rotated log files.</p><p></p><p><strong>Minimum value:</strong> <code>1</code></p><p></p><p><strong>Note:</strong> A log file is rotated every time the game starts.</p></td></tr><tr><td><code>max_file_size</code></td><td><code>integer</code></td><td><code>10</code></td><td>The maximum size, in megabytes, of a log file.<br><br><strong>Minimum value:</strong> <code>1</code></td></tr><tr><td></td><td></td><td></td><td></td></tr><tr><td><strong>plugins</strong></td><td></td><td></td><td></td></tr><tr><td><code>enabled</code></td><td><code>boolean</code></td><td><code>true</code></td><td>Enable / disable plugins system.</td></tr><tr><td><code>ignored</code></td><td><code>string[]</code></td><td><code>[]</code></td><td>The specified plugins are ignored and will not loaded.</td></tr><tr><td></td><td></td><td></td><td></td></tr><tr><td><strong>dev</strong></td><td></td><td></td><td></td></tr><tr><td><code>console</code></td><td><code>boolean</code></td><td><code>true</code></td><td>Enable / disable the external console (<strong>useful for development</strong>).</td></tr><tr><td><code>wait_for_debugger</code></td><td><code>boolean</code></td><td><code>false</code></td><td>Block the process until a debugger is attached.</td></tr></tbody></table>

## Example

An example of the configuration file.

```
version = 0

[logging]
level = "info"
flush_on = "info"
max_files = 5
max_file_size = 10

[plugins]
enabled = true
ignored = [ "RED4ext.Playgorund" ]

[dev]
console = false
wait_for_debugger = false
```


# Uninstalling

Guide how to uninstall RED4ext.

## Uninstalling RED4ext

1. **Remove** `d3d11.dll`, `powrprof.dll` or `winmm.dll` from `<game_directory>/bin/x64`.
2. (**Optionally**) Remove`red4ext` directory from `<game_directory>`.

## **Uninstalling a Plugin**

**Remove** the plugin's files / directory from `<game_directory>/red4ext/plugins`.


# RED4ext & RED4ext.SDK

## What is RED4ext?

[RED4ext](https://github.com/WopsS/RED4ext) 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.

## What is RED4ext.SDK?

[RED4ext.SDK](https://github.com/WopsS/RED4ext.SDK) 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;

## How can I browse the SDK?

See [Browse Red4Ext: NativeDB](/mod-developers/red4ext-and-red4ext.sdk/browse-red4ext-nativedb)


# Browse Red4Ext: NativeDB

Where to find the documentation

You can browse Red4Ext via Rayshader's excellent web tool [NativeDB](https://nativedb.red4ext.com/), where all documentation will be gathered and kept up-to-date by volunteers.

## [Link to NativeDB](https://nativedb.red4ext.com/)

If you want to get involved, check out the [github repository](https://rayshader.github.io/cp2077-nativedb) or this thread on the [REDmodding Discord](https://discord.com/channels/717692382849663036/1204386919727894548/1204386919727894548).


# Creating a Plugin

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:

* [CMake](https://cmake.org/)
* [Premake](https://premake.github.io/)
* [Visual Studio](https://visualstudio.microsoft.com/)

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):

* [CMake](https://github.com/WopsS/RED4ext.Example.CMake)
* [Premake](https://github.com/WopsS/RED4ext.Example.Premake)
* [Visual Studio](https://github.com/WopsS/RED4ext.Example.VisualStudio)

After you decide what build systen or toolchain you would like to use make sure to add [RED4ext.SDK](https://github.com/WopsS/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`).

{% hint style="info" %}
**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.
{% endhint %}

{% hint style="warning" %}
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](https://aka.ms/vs/17/release/vc_redist.x64.exe).
{% endhint %}

## Exported functions

### Supports

Specify the API version of the plugin.

#### Return

Returns the support API version supported by your plugins.

{% hint style="info" %}
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`.
{% endhint %}

### Query

This function is used to fill your plugin information, like name, author, supported game version, etc..

#### Parameters

* **RED4ext::PluginInfo\*** - The pointer to the structure that contains information about your plugin.

{% hint style="warning" %}
**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`.
{% endhint %}

### Main

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.

{% hint style="warning" %}
Memory allocators are not initialized yet. If you need to use RTTI system (call functions for example), see [Custom game states](/mod-developers/custom-game-states) to execute your code when RTTI system is ready.
{% endhint %}

#### Parameters

* **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.

#### Return

* `false` - if the plugin did not initialize properly.
* `true` - if the plugin initalized properly.

#### Remarks

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.

## Example

```cpp
#include <RED4ext/RED4ext.hpp>

RED4EXT_C_EXPORT bool RED4EXT_CALL Main(RED4ext::PluginHandle aHandle, RED4ext::EMainReason aReason, const RED4ext::Sdk* aSdk)
{
    switch (aReason)
    {
    case RED4ext::EMainReason::Load:
    {
        // Attach hooks, register RTTI types, add custom states or initalize your application.
        // DO NOT try to access the game's memory at this point, it is not initalized yet.
        break;
    }
    case RED4ext::EMainReason::Unload:
    {
        // Free memory, detach hooks.
        // The game's memory is already freed, to not try to do anything with it.
        break;
    }
    }

    return true;
}

RED4EXT_C_EXPORT void RED4EXT_CALL Query(RED4ext::PluginInfo* aInfo)
{
    aInfo->name = L"Plugin's name";
    aInfo->author = L"Author's name";
    aInfo->version = RED4EXT_SEMVER(1, 0, 0); // Set your version here.
    aInfo->runtime = RED4EXT_RUNTIME_LATEST;
    aInfo->sdk = RED4EXT_SDK_LATEST;
}

RED4EXT_C_EXPORT uint32_t RED4EXT_CALL Supports()
{
    return RED4EXT_API_VERSION_LATEST;
}
```


# Creating a Custom Native Class

When writing a RED4ext plugin in conjunction with a [Redscript](https://wiki.redmodding.org/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](https://github.com/WopsS/RED4ext.SDK/tree/master/examples/native_class_redscript).

## RED4ext Snippets

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):

```cpp
struct CustomController : RED4ext::IScriptable
{
    RED4ext::CClass* GetNativeType();
};
```

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.

```cpp
RED4ext::TTypedClass<CustomController> customControllerClass("CustomController");

RED4ext::CClass* CustomController::GetNativeType()
{
    return &customControllerClass;
}
```

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:

```cpp
void RegisterTypes()
{
    RED4ext::CRTTISystem::Get()->RegisterType(&customControllerClass);
}
```

The next block will manually set the parent of our type to `IScriptable`, to match the class.

```cpp
void PostRegisterTypes()
{
   auto rtti = RED4ext::CRTTISystem::Get();
   auto scriptable = rtti->GetClass("IScriptable");
   customControllerClass.parent = scriptable;
}
```

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:

```cpp
RED4EXT_C_EXPORT bool RED4EXT_CALL Main(RED4ext::PluginHandle aHandle,
    RED4ext::EMainReason aReason, RED4ext::RED4ext* aRED4ext)
{
    switch (aReason)
    {
        case RED4ext::EMainReason::Load:
        {
            RED4ext::RTTIRegistrator::Add(RegisterTypes, PostRegisterTypes);
            break;
        }
        case RED4ext::EMainReason::Unload:
        {
            break;
        }
    }
    
    return true;
}
```

## Redscript Snippet

On this side, the declaration is pretty simple, and similar to the headers from [the decompiled scripts](https://codeberg.org/adamsmasher/cyberpunk). Technically the `extends IScriptable` is implied for all classes, and can be omitted here:

```swift
public native class CustomController extends IScriptable {

}
```

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.


# Adding a Native Function

## RED4ext Snippets

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.

```cpp
void GetNumber(RED4ext::IScriptable* aContext, RED4ext::CStackFrame* aFrame,
    float* aOut, int64_t a4)
{
    RED4ext::Vector4 worldPosition;
    int32_t count;
    
    RED4ext::GetParameter(aFrame, &worldPosition);
    RED4ext::GetParameter(aFrame, &count);
    aFrame->code++; // skip ParamEnd
    
    if (aOut)
    {
        *aOut = 6.25;
    }
}
```

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:

```cpp
RED4EXT_C_EXPORT void RED4EXT_CALL PostRegisterTypes()
{
   // This section is from the previous page.
   auto rtti = RED4ext::CRTTISystem::Get();
   auto scriptable = rtti->GetClass("IScriptable");
   customControllerClass.parent = scriptable;

   auto getNumber = RED4ext::CClassFunction::Create(&customControllerClass, 
       "GetNumber", "GetNumber", &GetNumber, { .isNative = true });
   getNumber->AddParam("Vector4", "worldPosition");
   getNumber->AddParam("Int32", "count");
   getNumber->SetReturnType("Float");
   customControllerClass.RegisterFunction(getNumber);
}
```

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.&#x20;

## Redscript Snippets

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):

```swift
public native class CustomController extends IScriptable {
    public native func GetNumber(worldPosition: Vector4, count: Int32) -> Float;
}
```

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:

```swift
public class MyCustomClassPrinter extends ScriptableSystem {
    public func OnAttach() -> Void {
        LogChannel(n"DEBUG", "Hello!");
        let c = new CustomController();
        let vector = new Vector4(1.0, 2.0, 3.0, 4.0);
        let num = 50;
        LogChannel(n"DEBUG", "Number: " + FloatToString(c.GetNumber(vector, num)));
    }
}
```


# Custom game states

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.

## State functions

Every state has the following functions:

### OnEnter

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.

#### Return

* The return value is not taken in consideration. It is recommended to always return `true` for future proofing.

### OnUpdate

Called every frame. This function can contain more complex code.

#### Return

* `false` - if the state did not finish executing.
* `true` - if the state finished executing.

{% hint style="info" %}
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.
{% endhint %}

### OnExit

Called when the state is ending. This function is called once by the game, so be careful what you want to do here.

#### Return

* The return value is not taken in consideration. It is recommended to always return `true` for future proofing.

## Game's Life Cycle

![](/files/wrd6CpqKFzffq7PG4JJY)

## Example

```cpp
#include <RED4ext/RED4ext.hpp>

bool BaseInit_OnEnter(RED4ext::CGameApplication* aApp)
{
    return true;
}

bool BaseInit_OnUpdate(RED4ext::CGameApplication* aApp)
{
    static uint32_t i = 0;
    if (i == 3)
    {
        return true;
    }

    i++;
    return false;
}

bool BaseInit_OnExit(RED4ext::CGameApplication* aApp)
{
    return true;
}

bool Shutdown_OnUpdate(RED4ext::CGameApplication* aApp)
{
    static uint32_t i = 0;
    if (i == 3)
    {
        return true;
    }

    i++;
    return false;
}

RED4EXT_C_EXPORT bool RED4EXT_CALL Main(RED4ext::PluginHandle aHandle, RED4ext::EMainReason aReason, const RED4ext::Sdk* aSdk)
{
    switch (aReason)
    {
    case RED4ext::EMainReason::Load:
    {
        RED4ext::GameState initState;
        initState.OnEnter = &BaseInit_OnEnter;
        initState.OnUpdate = &BaseInit_OnUpdate;
        initState.OnExit = &BaseInit_OnExit;

        aSdk->gameStates->Add(aHandle, RED4ext::EGameStateType::BaseInitialization, &initState);
        
        RED4ext::GameState shutdownState;
        shutdownState.OnEnter = nullptr;
        shutdownState.OnUpdate = &Shutdown_OnUpdate;
        shutdownState.OnExit = nullptr;

        aSdk->gameStates->Add(aHandle, RED4ext::EGameStateType::Shutdown, &shutdownState);

        break;
    }
    case RED4ext::EMainReason::Unload:
    {
        break;
    }
    }

    return true;
}
```


# Logging

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.

## Example

```cpp
#include <RED4ext/RED4ext.hpp>

RED4EXT_C_EXPORT bool RED4EXT_CALL Main(RED4ext::PluginHandle aHandle, RED4ext::EMainReason aReason, const RED4ext::Sdk* aSdk)
{
    switch (aReason)
    {
    case RED4ext::EMainReason::Load:
    {
        aSdk->logger->Trace(aHandle, "Hello World!");
        aSdk->logger->TraceF(aHandle, "Hello %s!", "World");

        break;
    }
    case RED4ext::EMainReason::Unload:
    {
        break;
    }
    }

    return true;
}
```


# Creating a plugin with RedLib

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).

## Requirements

You must install RED4ext.SDK in your project like any other plugin (see [Creating a plugin](/mod-developers/creating-a-plugin)).\
You need to install [RedLib](https://github.com/psiberx/cp2077-red-lib). See the README to configure your CMake project.

## Setup plugin to register types

Now you can change the entry-point of your plugin like this:

```cpp
/// File: src\\main.cpp

#include <RED4ext/RED4ext.hpp>
// You must include RedLib. Note that it introduces an alias
// such as namespace RED4ext can be replaced by Red.
#include <RedLib.hpp>

RED4EXT_C_EXPORT bool RED4EXT_CALL Main(RED4ext::PluginHandle aHandle,
                                        RED4ext::EMainReason aReason,
                                        const RED4ext::Sdk* aSdk) {
  switch (aReason)  {
  case RED4ext::EMainReason::Load: {
    // It will automatically register types declared below.
    Red::TypeInfoRegistrar::RegisterDiscovered();
    break;
  }
  case RED4ext::EMainReason::Unload: {
    break;
  }
  }
  return true;
}

// ...
```

## Declare new classes

We are going to create a zoo, and name our mod... `Zoo`. Now lets create a generic `Animal` class:

```cpp
/// File: src\\Animal.hpp

#include <RED4ext/Scripting/Natives/Generated/Vector4.hpp>
#include <RedLib.hpp>

class Animal : public Red::IScriptable {
public:
  //Animal() = default;

  virtual bool CanFly() const {
    return false;
  }
  virtual bool CanWalk() const {
    return false;
  }

  virtual bool is_carnivore() const {
    return false;
  }
  virtual bool is_herbivore() const {
    return false;
  }

  Red::Vector4 position{};

  RTTI_IMPL_TYPEINFO(Animal);
  RTTI_IMPL_ALLOCATOR();
}

RTTI_DEFINE_CLASS(Animal, {
  // You only need to add an alias when declaring scripts 
  // with 'module' and 'import' keywords.
  RTTI_ALIAS("Zoo.Animal");

  RTTI_ABSTRACT();

  RTTI_METHOD(CanFly);
  RTTI_METHOD(CanWalk);

  // You can use another name to declare instead.
  RTTI_METHOD(is_carnivore, "IsCarnivore");
  RTTI_METHOD(is_herbivore, "IsHerbivore");
  
  RTTI_GETTER(position);
});
```

Now lets add a `Wolf` to our zoo:

```cpp
/// File: src\\Wolf.hpp

#include <RedLib.hpp>

#include "Animal.hpp"

class Wolf : public Animal {
public:
  //Wolf() = default;

  bool CanWalk() const override {
    return true;
  }

  bool IsCarnivore() const override {
    return true;
  }

  bool CanHunt() const {
    return true;
  }

  RTTI_IMPL_TYPEINFO(Wolf);
  RTTI_IMPL_ALLOCATOR();
};

RTTI_DEFINE_CLASS(Wolf, {
  RTTI_ALIAS("Zoo.Wolf");

  RTTI_PARENT(Animal);

  // Redeclare methods you override.
  RTTI_METHOD(CanWalk);
  RTTI_METHOD(is_carnivore, "IsCarnivore");

  RTTI_METHOD(CanHunt);
});
```

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:

```swift
/// File: scripts\\Zoo.reds

// Again, declaring native types within a module
// is not required.
module Zoo

public abstract native class Animal extends IScriptable {
  public native func CanFly() -> Bool;
  public native func CanWalk()-> Bool;

  public native func IsCarnivore() -> Bool;
  public native func IsHerbivore() -> Bool;

  public native func GetPosition() -> Vector4;
}

public native class Wolf extends Animal {
  // You don't need to redeclare methods of the parent,
  // even when you override them.

  // But you have to declare new methods.
  public native func CanHunt() -> Bool;
}
```

Lets create our zoo somewhere when the game starts:

```swift
/// File: scripts\\ZooTest.reds

import Zoo.*

public class ZooSystem extends ScriptableSystem {
  private let m_animals: array<ref<Animal>>;

  private func OnAttach() {
    // Create a pack of wolves.
    ArrayPush(this.m_animals, new Wolf());
    ArrayPush(this.m_animals, new Wolf());
    ArrayPush(this.m_animals, new Wolf());
    ArrayPush(this.m_animals, new Wolf());

    for animal in this.m_animals {
      LogChannel(n"Info", s"Class name: s\(animal.GetClassName())");
      LogChannel(n"Info", "");
      LogChannel(n"Info", s"Can fly? s\(animal.CanFly())");
      LogChannel(n"Info", s"Can walk? s\(animal.CanWalk())");
      LogChannel(n"Info", s"Is carnivore? s\(animal.IsCarnivore())");
      LogChannel(n"Info", s"Is herbivore? s\(animal.IsHerbivore())");
      let wolf = animal as Wolf;

      LogChannel(n"Info", "");
      LogChannel(n"Info", s"Can hunt? \(wolf.CanHunt())");
      LogChannel(n"Info", "");
    }
  }

  private func OnDetach() {
    ArrayClear(this.m_animals);
  }

}
```

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.

## Conclusion

This is a simple introduction to RedLib and how it can make your life easier when writing plugin with [RED4ext.SDK](https://github.com/WopsS/RED4ext.SDK). You should definitively go to the [GitHub repository](https://github.com/psiberx/cp2077-red-lib/) and read through the entire README to learn about all the features it provides.

Happy coding!


# Installing a plugin with red-cli

This guide will show you how you can quickly install a plugin in your game's folder after building it.

## Introduction

[red-cli](https://github.com/rayshader/cp2077-red-cli) 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.

{% hint style="info" %}
This tool is also compatible with Redscript. See [this guide](https://docs.red4ext.com/mod-developers/spaces/-McniwB8YOK2HnJ7SYg_/pages/jw2RZ5aFUSgpc07Bh6LB#id-4.-bundle-with-red-cli) if you are also writing scripts in addition to a RED4ext plugin.
{% endhint %}

## Setup red-cli

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.

See the [red-cli README](https://github.com/rayshader/cp2077-red-cli) for information on its install and configuration.

## Setup CMake

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:

```cmake
## Debug mode: install scripts (+ tests) and plugin in game folder.
## Release mode: create archive with bundled scripts and plugin.
add_custom_command(
        TARGET ${CMAKE_PROJECT_NAME}
        POST_BUILD
        WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
        COMMENT "$<$<CONFIG:Debug>:Install scripts with red-cli>" "$<$<CONFIG:Release>:Build archive with red-cli>"
        COMMAND "$<$<CONFIG:Debug>:red-cli;install>" "$<$<CONFIG:Release>:red-cli;pack>"
        COMMAND_EXPAND_LISTS
)
```

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.


