> For the complete documentation index, see [llms.txt](https://wiki.redmodding.org/scripting-cyberpunk/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://wiki.redmodding.org/scripting-cyberpunk/redscript/common-patterns/handling-player-life-cycle-events.md).

# Handling Player Life-Cycle Events

How to register callbacks for when the player object is attached and detached

The [`PlayerSystem`](https://nativedb.red4ext.com/PlayerSystem) implements methods to register callbacks for when the player object is attached and detached. In your [`ScriptableSystem`](/scripting-cyberpunk/redscript/language-reference/scriptables/scriptablesystem.md)'s respective lifecycle method, you can register your system to the `PlayerSystem`.

This way, your methods will always be called when the respective event occurs.

```swift
module MyMod

public class MySystem extends ScriptableSystem {
  protected let m_playerAttachedCallbackID: Uint32;

  protected let m_playerDetachedCallbackID: Uint32;

  protected func RegisterPlayerCallbacks() -> Void {
    let playerSystem: ref<PlayerSystem> = GameInstance.GetPlayerSystem(this.GetGameInstance());

    this.m_playerAttachedCallbackID = playerSystem.RegisterPlayerPuppetAttachedCallback(this, n"OnPlayerAttached");
    this.m_playerDetachedCallbackID = playerSystem.RegisterPlayerPuppetDetachedCallback(this, n"OnPlayerDetached");
  }

  protected func UnregisterPlayerCallbacks() -> Void {
    let playerSystem: ref<PlayerSystem> = GameInstance.GetPlayerSystem(this.GetGameInstance());

    playerSystem.UnregisterPlayerPuppetAttachedCallback(this.m_playerAttachedCallbackID);
    playerSystem.UnregisterPlayerPuppetDetachedCallback(this.m_playerDetachedCallbackID);

    this.m_playerAttachedCallbackID = 0u;
    this.m_playerDetachedCallbackID = 0u;
  }

  public func OnAttach() -> Void {
    this.RegisterPlayerCallbacks();
  }

  public func OnDetach() -> Void {
    this.UnregisterPlayerCallbacks();
  }

  protected func OnPlayerAttached(playerPuppet: ref<GameObject>) -> Void {
    FTLog(s"\(this.GetClassName())#OnPlayerAttached");
  }

  protected func OnPlayerDetached(playerPuppet: ref<GameObject>) -> Void {
    FTLog(s"\(this.GetClassName())#OnPlayerDetached");
  }
}
```

## Bugged Callbacks

[`ScriptableSystem`](/scripting-cyberpunk/redscript/language-reference/scriptables/scriptablesystem.md) (kind of) supports [non-documented](https://nativedb.red4ext.com/c/5802799602997948) methods to handle the player object's life-cycle events when the player object is attached and detached from the game. It's a common pattern to see mods and snippets follow this example (as it's what the game does as well) but it does have a few bugs/problems.

Those methods being the following:

```swift
protected func OnPlayerAttach(request: ref<PlayerAttachRequest>)
protected func OnPlayerDetach(request: ref<PlayerDetachRequest>)
```

The issue being that `OnPlayerDetach` doesn't seemed to be called at all and `OnPlayerAttach` seems to have some pitfalls.

Thanks to the insight from DarkFortuneTeller, it seems like the player object for V and Johnny in act 1 and act 2 are different instances for some reason. This causes `OnPlayerAttach` for `ScriptableSystem`s to not fire when the switch happens, which then causes your mod to fail unexpectedly as your code isn't ran. The problem goes away after a reload as it causes `OnPlayerAttach` to run again on the controlled `PlayerPuppet`.

To fix this problem, you can instead manually register callbacks to handle these events as seen above.

<details>

<summary>For more information about the bugged callbacks</summary>

```swift
module MyMod

public class MySystem extends ScriptableSystem {
  public func OnAttach() -> Void {
    FTLog(s"\(this.GetClassName())#OnAttach");
  }

  public func OnDetach() -> Void {
    FTLog(s"\(this.GetClassName())#OnDetach");
  }

  protected func OnPlayerAttach(request: ref<PlayerAttachRequest>) -> Void {
    FTLog(s"\(this.GetClassName())#OnPlayerAttach");
  }

  protected func OnPlayerDetach(request: ref<PlayerDetachRequest>) -> Void {
    FTLog(s"\(this.GetClassName())#OnPlayerDetach");
  }
}
```

When loading in a save, here's the logs:

```
MyMod.MySystem#OnAttach <- main menu attach
MyMod.MySystem#OnDetach <- main menu detach
MyMod.MySystem#OnAttach <- attaching to game session
MyMod.MySystem#OnPlayerAttach <- attaching to the player in the game session
```

When re-loading a save, the mod prints the following:

```
MyMod.MySystem#OnDetach
MyMod.MySystem#OnAttach
MyMod.MySystem#OnPlayerAttach
```

Note that the `OnPlayerDetach` isn't called at all.

</details>
