🖍️
RED4ext Plugin Dev
HomeRED ModdingDiscordGitHub
  • Home
  • Getting Started
    • Installing RED4ext
    • Installing a Plugin
    • Configuration
    • Uninstalling
  • Mod Developers
    • RED4ext & RED4ext.SDK
      • Browse Red4Ext: NativeDB
    • Creating a Plugin
    • Creating a Custom Native Class
    • Adding a Native Function
    • Custom game states
    • Logging
    • Creating a plugin with RedLib
    • Installing a plugin with red-cli
  • Utils
    • NativeDB
    • CRC32 Hasher
    • FNV1A64 Hasher
Powered by GitBook
On this page
  • Requirements
  • Setup plugin to register types
  • Declare new classes
  • Conclusion
Edit on GitHub
Export as PDF
  1. Mod Developers

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

PreviousLoggingNextInstalling a plugin with red-cli

Last updated 9 months ago

Requirements

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.

Setup plugin to register types

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

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

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

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

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

/// 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

Happy coding!

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.

Creating a plugin
RedLib
RED4ext.SDK
GitHub repository