For the complete documentation index, see llms.txt. This page is also available as Markdown.

Hook Annotations

Special keywords that you can use to change or extend the behavior of existing methods and classes in the base game.

Hook annotations allow you to hook into the game functions, monitor or change how they behave and add your own functionality.

If you want to see how to create a hook, check following guide:

How to create a hook

If you don't know what to hook see:

Things to hook

You can't wrap native methods, but CET can. You may be able to have a custom system event and use CET to dispatch your custom event when observing the native method, allowing you to handle when the native method is called.

This depends on whether if the game calls the RTTI wrapper for the method, and not the underlying native method.

You can now generate declaration for annotations using NativeDB. You need to configure option Clipboard syntax to REDscript. You can click on the "copy" button of a function, pick a feature and it will copy the code in your clipboard.

@wrapMethod(class)

Hooks into an existing method with the same name and parameters on a specified class.

Your function will execute instead of the original method whenever it is invoked, but you can still access the underlying method by using the wrappedMethod(…) identifier. You would typically invoke the wrapped method in your newly defined function and forward all the arguments unchanged to preserve it's original behavior, but you can also modify the arguments or the final return value if you wish.

Furthermore, this annotation can be applied multiple times to chain multiple functions that modify the same method. Each function in the chain wraps around the previous one. This helps to keep mods compatible even if they alter the same methods. For example, multiple mods can use this annotation to append new buttons to the main menu:

@wrapMethod(SingleplayerMenuGameController)
private func PopulateMenuItemList() {
  wrappedMethod(); // This will call the original PopulateMenuItemList
  this.AddMenuItem("BUTTON 1", n"OnDebug");
}

// You can use this annotation to chain multiple functions
@wrapMethod(SingleplayerMenuGameController)
private func PopulateMenuItemList() {
  wrappedMethod(); // This will run the previous function with this annotation
  this.AddMenuItem("BUTTON 2", n"OnDebug");
}

// The result will be two new buttons added to the main menu

When you use wrappedMethod(…) to call the original method, make sure to match the arguments for the correct overload of the method.

You should usually call wrappedMethod(…) in your wrapper function. However, you can use a conditional statement to decide when to call it if you don’t need it in some situations.

@addMethod(class)

Creates a new method and adds it to an existing class.

For example, you can write a new method to disassemble all junk items in your backpack and add it to the BackpackMainGameController class:

@replaceMethod(class)

Completely replaces the original method with your own.

If possible you should prefer to use @wrapMethod(class) for compatibility.

This annotation is compatible with @wrapMethod. It will always overwrite the original method and it will not affect the functions that wrap around it.

@replaceGlobal()

Completely replaces the original global function with your own.

@addField(class)

Creates a new field and adds it to an existing class. For example, you can add a dummy field of type Int32 to the PlayerPuppet class:

Last updated