> 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/scripting/game-systems/journal/listening-to-journal-updates.md).

# Listening to Journal Updates

How to do something when a journal entry has met a specific state

With the [`JournalManager`](https://nativedb.red4ext.com/JournalManager), you can register a listener to call a custom method whenever a journal entry's state has changed. You can implement this to track the state of an entry, allowing you to know when the player has finished a specific quest objective, quest, received a specific message, or something else in regards to the data that the journal stores.&#x20;

To register a listener, you'll need to know either the hash or the full path and class name of the entry you want to track.

## Listening To Quest Updates

As an example, we'll create a listener to track when the state of the `Leave the apartment.` objective in the quest `Playing for Time`, which is the quest after the heist which (I think) can be used to determine when the player has finished the prologue.&#x20;

Using the information from the [quest dumps](/scripting-cyberpunk/scripting/game-systems/journal.md#quest-dump), here is the relevant information for this specific objective:

```json
{
  "hash": 1674165884,
  "path": "quests/main_quest/act_01/q101_resurrection/base/prepare_before_leave",
  "type": "Primary",
  "description": "Leave the apartment.",
  "district": "Watson",
  "entries": [
    {
      "hash": 3729107626,
      "path": "quests/main_quest/act_01/q101_resurrection/base/prepare_before_leave/leave_mp",
      "type": "MapPin",
      "ref": "#q101_mp_leave_v_room",
      "pos": [-1389.6557617188,1271.1151123047,124.59104919434]
    }
  ]
}
```

{% hint style="info" %}
To find the hash for a specific quest (or objective, phase, etc.), take a look at the [dumps](/scripting-cyberpunk/scripting/game-systems/journal.md#quest-dump) section in the Journal page.
{% endhint %}

With this, all we need is the `hash`.

### Registering the Listener

When listening for the quest, we'll look for either the `Succeeded` or `Active` state, as this should represent when the player has finished the prologue and is free to go throughout the world in act 2.

{% tabs %}
{% tab title="Redscript" %}

```swift
class JournalEntryStateListener extends ScriptableSystem {
  protected let m_journal: ref<JournalManager>;

  protected let m_entryHash: Uint32;

  protected let m_acceptedStates: [gameJournalEntryState];

  public final func OnPlayerAttach(request: ref<PlayerAttachRequest>) -> Void {
    this.m_journal = GameInstance.GetJournalManager(this.GetGameInstance());
    this.m_entryHash = 1674165884u;
    this.m_acceptedStates = [gameJournalEntryState.Active, gameJournalEntryState.Succeeded];

    this.m_journal.RegisterScriptCallback(this, n"OnJournalUpdate", gameJournalListenerType.State);
    this.DoSomething();
  }

  public func OnAttach() -> Void {
    return;
  }

  public func OnDetach() -> Void {
    this.m_journal.UnregisterScriptCallback(this, n"OnJournalUpdate");
    this.m_journal = null;
  }

  public func GetEntryState() -> gameJournalEntryState {
    return this.m_journal.GetEntryState(this.m_journal.GetEntry(this.m_entryHash));
  }

  public func IsEntryFulfilled() -> Bool {
    return ArrayContains(this.m_acceptedStates, this.GetEntryState());
  }

  protected cb func OnJournalUpdate(hash: Uint32, className: CName, notifyOption: JournalNotifyOption, changeType: JournalChangeType) -> Bool {
    if Equals(this.m_entryHash, hash) {
      this.DoSomething();
    }
  }

  public func DoSomething() -> Void {
    FTLog(s"\(this.GetClassName())#DoSomething | \(this.GetEntryState()) | \(this.IsEntryFulfilled())");

    // do something based on the state - https://nativedb.red4ext.com/gameJournalEntryState
  }

  public final static func GetInstance(gameInstance: GameInstance) -> ref<JournalEntryStateListener> {
    return GameInstance.GetScriptableSystemsContainer(gameInstance).Get(NameOf<JournalEntryStateListener>()) as JournalEntryStateListener;
  }
}
```

As this is a [scriptable](/scripting-cyberpunk/redscript/language-reference/scriptables.md), you can get access to this class in another point of your code with `JournalEntryStateListener.GetInstance(gameInstance)` and use the `IsEntryFulfilled()` or `GetEntryState()`.
{% endtab %}

{% tab title="Lua" %}
{% hint style="info" %}
This snippet uses [`GameSession`](https://github.com/psiberx/cp2077-cet-kit/blob/main/GameSession.lua) from psiberx's [cet kit](https://github.com/psiberx/cp2077-cet-kit) to run the listener when a game session starts.
{% endhint %}

```lua
local GameSession = require("GameSession")

registerForEvent('onInit', function()
  local entryHash = 1674165884
  local acceptedStates = { gameJournalEntryState.Active, gameJournalEntryState.Succeeded }

  local journalManager = GameInstance.GetJournalManager()

  function GetEntryState()
    return journalManager:GetEntryState(journalManager:GetEntry(entryHash))
  end

  function IsEntryFulfilled()
    local state = GetEntryState()

    for i, enum in ipairs(acceptedStates) do
      if enum == state then
        return true
      end
    end

    return false
  end

  function DoSomething()
    print("state: " .. GetEntryState().value .. " | " .. "is fulfilled: " .. tostring(IsEntryFulfilled()))

    -- -- do something based on the state - https://nativedb.red4ext.com/gameJournalEntryState
  end

  local function OnJournalUpdate(hash, className, notifyOption, changeType)
    if entryHash == hash then
      DoSomething()
    end
  end

  local callback = NewProxy({
    OnJournalUpdate = {
      args = {"Int32", "CName", "gameJournalNotifyOption", "gameJournalChangeType"},
      callback = OnJournalUpdate
    }
  })

  GameSession.OnStart(function(state)
    journalManager:RegisterScriptCallback(callback:Target(), callback:Function("OnJournalUpdate"), gameJournalListenerType.State)
    DoSomething()
  end)
end)
```

{% endtab %}
{% endtabs %}

### Changes

Note that the listener is called whenever *any* journal entry is updated, so all you need to do is to update the `OnJournalUpdate` function to properly reflect the hash of the entry you want to track.
