Skip to content

v1.3.0

Latest

Choose a tag to compare

@atoshit atoshit released this 14 Mar 11:53
· 1 commit to main since this release

ZedLib — Backend refactoring changes

Summary

Full refactor of the Lua backend: NUI message batching, reactive menu items with watcher, validation, debug mode, and optimisations. Public API remains backward compatible.


1. Performance and NUI latency

  • Batching: All NUI messages go through ZedInternal.SendNUI(action, data) and are flushed once per frame in a single zedlib:batch payload. No more consecutive SendNUIMessage calls.
  • Load order: lua/api/_init.lua is loaded before lua/client.lua so the buffer and SendUI are defined first.
  • NUI: New handler zedlib:batch in messageHandlers.ts dispatches each message in the batch to the existing handlers.
  • Ticks: Context loop uses Wait(100) when ALT is not held (was 150). Interact loop uses Wait(200) when no interact point is registered.
  • Context: Model hashes are cached in ZedState.modelHashCache to avoid repeated GetHashKey().
  • Callbacks: Import wrapper uses resource-specific events __zedlib_cb_{resourceName}_{id} when the callback id matches res:cb:num; otherwise falls back to zedlib:triggerCallback.

2. Dynamic item refresh (reactive values)

  • Reactive properties: For menu items, label, rightLabel, rightLabelColor, infoData, and checked (checkbox) can be functions. They are called when building the item and periodically by the watcher.
  • Watcher (lua/api/watcher.lua): A thread runs at ZedConfig.refreshInterval (default 100 ms) only when ZedInternal.menuOpen is true and at least one item has reactive props. It evaluates functions, compares with a cache (deep compare for tables), and sends zedlib:updateItem with a partial patch when something changes.
  • Manual refresh:
    • zed.RefreshItem(menuId, itemId, patch) — sends a partial update for one item.
    • zed.RefreshMenu(menuId) — re-serialises and resends all items of the menu.
  • NUI: New handlers zedlib:updateItem and zedlib:refreshMenu. menuStore has replaceItems(menuId, items) for full menu refresh.

3. Menu storage and validation

  • State: Menus are stored in ZedState.menus[menuId] with items and categories. Each item keeps the raw opts (including functions). ZedState.menuItemsById[menuId][itemId] gives O(1) lookup.
  • Validation: All public menu/dialog/context/progress functions validate arguments and use ZedInternal.assert(component, condition, message) on failure. Warnings (e.g. category does not exist yet, progress already active) go through ZedInternal.log("WARN", ...).
  • Helpers: ZedInternal.validateHex(s), ZedInternal.parseBaseItem(opts) in _init.lua. Dialog validates input types and button variants; ProgressBar validates duration, anim (dict/clip), prop (model); AddContextOption validates exactly one of type/entity/model and optional submenu.

4. Debug mode

  • Config: ZedConfig.debug (default false), ZedConfig.debugFilter (optional table of components, e.g. {"MENU", "NUI"}), ZedConfig.refreshInterval (default 100).
  • Runtime: zed.SetConfig({ debug = true }), zed.SetConfig({ debugFilter = {"MENU"} }) update ZedConfig and are passed to NUI via zedlib:setConfig.
  • Logger: ZedInternal.log(level, component, message, data) with level DEBUG/INFO/WARN/ERROR. Only runs when ZedConfig.debug is true; if debugFilter is set, only listed components are logged.
  • Command: RegisterCommand('zeddebug', ...) toggles ZedConfig.debug in-game.
  • Errors: All previous print() error paths (menu/dialog/context/interact callbacks) now use ZedInternal.log("ERROR", component, message, nil).

5. File and API changes

File Changes
config.lua Added refreshInterval, debug, debugFilter.
fxmanifest.lua _init.lua before client.lua; added watcher.lua.
lua/client.lua SendUI removed (uses _init); callback errors use ZedInternal.log; context wait 100 when ALT not held.
lua/api/_init.lua ZedState, ZedConst, ZedInternal (SendNUI, assert, log, validateHex, parseBaseItem, fireCallback with resource events), flush thread, SendUI, zeddebug command.
lua/api/menu.lua Full validation; menus/items stored in ZedState; reactive resolution; RefreshItem, RefreshMenu.
lua/api/watcher.lua New. Watcher thread and reactive evaluation.
lua/api/context.lua Model hash cache; validations; errors via log.
lua/api/dialog.lua Validations for inputs/buttons/color.
lua/api/progressbar.lua Validations; warning when already active; errors via log.
lua/api/interact.lua Wait 200 when no config/best; callback errors via log.
lua/api/config.lua SetConfig merges debug, debugFilter, refreshInterval into ZedConfig.
lua/api/exports.lua Doc block; exports RefreshItem, RefreshMenu.
import.lua RefreshItem, RefreshMenu; storeCb registers __zedlib_cb_*; ZedConfigOptions extended.
web/.../handlers.ts dispatchNuiAction export.
web/.../messageHandlers.ts zedlib:batch, zedlib:updateItem, zedlib:refreshMenu.
web/.../menuStore.ts replaceItems(menuId, items).

6. Breaking changes

  • None to the existing public API. All existing function signatures and behaviour are preserved.
  • Reactive values: Passing a function for label, rightLabel, rightLabelColor, infoData, or checked is new; static values behave as before.

7. New APIs

  • zed.RefreshItem(menuId, itemId, patch) — partial update for one menu item.
  • zed.RefreshMenu(menuId) — full refresh of menu items to NUI.
  • zed.SetConfig({ debug = true | false, debugFilter = {"MENU", "NUI"}, refreshInterval = 100 }) — runtime config.
  • In-game: /zeddebug toggles debug mode.