# Observe

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](/cyber-engine-tweaks/cet-functions/events/oninit.md) event, in the `init.lua` file.&#x20;

{% hint style="info" %}
You can find a list of [things to observe ](https://wiki.redmodding.org/redscript/language/intro/how-to-create-a-hook/things-to-hook)in the RedScript wiki.
{% endhint %}

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.

{% hint style="info" %}
You can now generate Observable and ObservableAfter using [NativeDB](https://nativedb.red4ext.com). 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.
{% endhint %}

## Definition

```lua
Observe(className, method, callback) -- alias of ObserveBefore()
```

```lua
ObserveBefore(className, method, callback)
```

```lua
ObserveAfter(className, method, callback)
```

```lua
--
-- ObserveBefore()
--
-- @param  string    className  The parent class name
-- @param  string    method     The method name to target
-- @param  function  callback   The callback function
--
ObserveBefore('className', 'method', function(self [, arg1, arg2, ...])
    
    -- method() has just been called
    
end)
```

```lua
--
-- ObserveAfter()
--
-- @param  string    className  The parent class name
-- @param  string    method     The method name to target
-- @param  function  callback   The callback function
--
ObserveAfter('className', 'method', function(self [, arg1, arg2, ...])
    
    -- method() has been called and fully executed
    
end)
```

{% hint style="info" %}
`Observe()` is an alias of `ObserveBefore()`. They both work the same.
{% endhint %}

{% hint style="warning" %}
If you observe a **static** function, you must define the field *'method'* with the full name of the function. Otherwise it won't work. You can find the full name using [NativeDB](https://nativedb.red4ext.com/). See [below](#observe-event-send-to-an-animationcontrollercomponent-click-on-functions-name-in-nativedb-to-copy-th) for an example.
{% endhint %}

## Representation

Here is a visual representation showing where observers are executed in the game's script:

```swift
public class AimingStateEvents extends UpperBodyEventsTransition {

    protected func OnEnter(stateContext: ref<StateContext>, scriptInterface: ref<StateGameScriptInterface>) -> Void {
        
        // ObserveBefore('AimingStateEvents', 'OnEnter')
        
        let aimingCost: Float;
        let focusEventUI: ref<FocusPerkTriggerd>;
        let timeDilationFocusedPerk: Float;
        let weaponType: gamedataItemType;
        let player: ref<PlayerPuppet> = scriptInterface.executionOwner as PlayerPuppet;
        // ...
        
        // ObserveAfter('AimingStateEvents', 'OnEnter')
        
    }

}
```

In this representation, the observer callback would be filled with the following arguments:

```lua
Observe('AimingStateEvents', 'OnEnter', function(self, stateContext, scriptInterface)
    
    -- self             the 'AimingStateEvents' class
    -- stateContext     the original method argument
    -- scriptInterface  the original method argument
    
end)
```

{% hint style="info" %}
The `self` parameter can be renamed at your convenience:

* `_`
* `this`
* `class`
* `whatever`
  {% endhint %}

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

## Usage Examples

#### Give money each time the player crouches:

{% code title="init.lua" %}

```lua
-- onInit
registerForEvent('onInit', function()
    
    -- observe crouch OnEnter state
    Observe('CrouchEvents', 'OnEnter', function(self, stateContext, scriptInterface)
        
        Game.AddToInventory('Items.money', 1000)
        
    end)
    
end)
```

{% endcode %}

#### Give money as long as the player is crouched:

{% code title="init.lua" %}

```lua
-- onInit
registerForEvent('onInit', function()
    
    -- observe crouch OnUpdate state
    -- this is triggered continuously, as long as the player is crouched
    Observe('CrouchEvents', 'OnUpdate', function(self, timeDelta, stateContext, scriptInterface)
        
        Game.AddToInventory('Items.money', 20)
        
    end)
    
end)
```

{% endcode %}

#### Observe event send to an [AnimationControllerComponent](https://nativedb.red4ext.com/AnimationControllerComponent#PushEvent) (click on function's name in NativeDB to copy the full name in your clipboard):

```lua
-- init.lua

-- onInit
registerForEvent('onInit', function()

  -- NativeDB will copy 'entAnimationControllerComponent::PushEvent;GameObjectCName'
  -- We can ignore the left part to only keep:
  Observe('AnimationControllerComponent', 'PushEvent;GameObjectCName', function(gameObject, eventName)
    print('GameObject:', gameObject:GetClassName())
    print('Event:', eventName)
  end)

end)
```

## Advanced Example

#### Give money when the player is crouched and in ADS:

{% code title="init.lua" %}

```lua
-- set initial vars
isADS = false
isCrouch = false

-- decide to give money
-- this function can be defined outside of onInit
-- as it is only called within observers
shouldGiveMoney = function()
    
    -- is in ADS and is crouched
    if isADS and isCrouch then
        Game.AddToInventory('Items.money', 1000)
    end

end

-- onInit
registerForEvent('onInit', function()
    
    -- observe ADS OnEnter state
    Observe('AimingStateEvents', 'OnEnter', function(self, stateContext, scriptInterface)
        
        isADS = true
        shouldGiveMoney()
        
    end)
    
    -- observe ADS OnExit state
    Observe('AimingStateEvents', 'OnExit', function(self, stateContext, scriptInterface)
        isADS = false -- reset condition
    end)
    
    -- observe Crouch OnEnter state
    Observe('CrouchEvents', 'OnEnter', function(self, stateContext, scriptInterface)
        
        isCrouch = true
        shouldGiveMoney()
        
    end)
    
    -- observe Crouch OnExit state
    Observe('CrouchEvents', 'OnExit', function(self, stateContext, scriptInterface)
        isCrouch = false -- reset condition
    end)

end)
```

{% endcode %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://wiki.redmodding.org/cyber-engine-tweaks/cet-functions/observers/observe.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
