F.A.Q

4 min readUpdated Today

Setup

Set Config.Locale in shared/config.lua:

shared/config.lua
1Config.Locale = 'en'
  1. Verify the item name matches Config.DiaryItemName
  2. In metadata mode the item must have a metadata.serial. The first use auto-generates one if missing, confirm your inventory accepts Bridge.SetItemMeta
  3. Check the F8 console for UI errors

Config.DiaryMode = 'metadata' keys the diary on the item's serial. The diary is a transferable physical object: any player who holds the item can read it, write notes, and unlock discoveries. Lose the item, lose access, until someone else picks it up. The original creator is recorded for audit only and does not gate access.

Config.DiaryMode = 'license' keys the diary on the player's identifier. Any diary item the player picks up opens their personal logbook. Other players cannot read it, even if they hold a diary item that previously belonged to that license.

Diary Sharing

Yes, in metadata mode. The diary travels with the item. Whoever currently holds it can read every page, add new discoveries while exploring, and write personal notes. When the item changes hands, the state bag re-syncs automatically on the new holder's client.

In license mode the diary is bound to the player's identifier and cannot be transferred.

In metadata mode the data follows the item. The diary serial stays in the database, so if the item is recovered the data is intact. If the item is permanently destroyed, the data is orphaned but not deleted (cache is evicted after 30 minutes of no access).

In license mode the data is tied to the player's identifier and survives any number of diary item losses.

Yes, in metadata mode. The diary item is the access token, possession is the rule. This enables RP scenarios like rival explorers stealing each other's research.

If you want diaries to be unstealable, switch to 'license' mode.

Discoverables

Add an entry to Config.Discoverables with a unique key:

shared/config.lua
1Config.Discoverables['my_animal'] = {
2    type        = 'model',
3    model       = 'a_c_deer',
4    name        = 'Deer',
5    subTitle    = 'Forest Animal',
6    description = 'Found in wooded areas.',
7    collection  = 'fauna',
8    icon        = 'fa-paw',
9    image       = 'https://your-image-url.png',
10    imageStyle  = 'sketch',
11    layoutStyle = 'vertical',
12}

The collection field must match a category key in Config.Book.encyclopedia.categories.

  • model: Triggers when the player targets a specific prop or ped model
  • sphere: Triggers when the player enters a sphere zone (requires coords and radius)
  • box: Triggers when the player enters a box zone (requires coords, size, optional rotation)
  • item: Triggers when the player holds a specific item in the inventory (requires item). Polled every 5 seconds via Bridge.HasItem, compatible with every inventory supported by ml_bridge.

All four are validated server-side. Zone and model unlocks check player range, item unlocks check actual possession. Forged attempts are rejected and logged to the exploits webhook.

Yes. Use the server export:

lua
1exports.ml_diary:unlockDiscovery(source, 'my_discovery_key')

The key must exist in Config.Discoverables. Returns false if the player has no diary or the key is invalid.

Five frame styles: 'polaroid', 'taped', 'sketch', 'noir', 'stamp'. Set via imageStyle on each discoverable.

Personal Notes

In the diaries database table, keyed on the diary's serial (or LICENSE-<identifier> in license mode). Each row stores the discoveries and personal notes as JSON in MEDIUMTEXT columns.

Every Config.SaveInterval minutes (default: 10). Only diaries flagged as dirty are written. onResourceStop flushes everything dirty on shutdown, and playerDropped flushes the diary that player had open.

Yes. Players can tear a page from their diary, which produces a diary_page item. Other players can use that item to insert the page into their own diary. The torn page carries the full content via item metadata.

Yes, via addPersonalNote:

lua
1local ok, noteId = exports.ml_diary:addPersonalNote(source, {
2    title   = 'Quest Update',
3    type    = 'text',
4    content = 'You found a hidden door...',
5})

These pages bypass `Config.PersonalPageLimit`: your script can always add page #16 even when the player has filled their personal pages. They are marked external = true and the user cannot edit or delete them from the in-game UI. Use removePersonalNote(source, noteId) to remove them later. The hard size cap (Config.MaxDiaryTotalSize, default 4 MB total) is still enforced.

Yes. noteContainsKeywords runs a single concatenated scan over every note's title and content:

lua
1-- All keywords must appear (default mode)
2local matched = exports.ml_diary:noteContainsKeywords(src,
3    { 'safe', 'Elix Gen', 'door' })
4
5-- Any one is enough
6exports.ml_diary:noteContainsKeywords(src,
7    { 'door', 'gate' }, { mode = 'any' })
8
9-- Lua patterns (regex-lite) for codes like "lab12" or "lab-7"
10exports.ml_diary:noteContainsKeywords(src,
11    'lab%-?%d+', { pattern = true })

Useful for "if the player documented X, unlock Y" mechanics.

Updates

  1. Download latest from CFX Portal
  2. Backup shared/config.lua and server/config_server.lua
  3. Replace all files except those two
  4. Restart the resource

Diary data, personal pages, and discoveries are stored in the database and survive updates.