-- ============================================= -- This file contains any strictly *pure* functions -- that are utilized by the rest of the menu. -- Many of them need to be available with menu disabled -- ============================================= --- Send a persistent alert to NUI ---@param key string An unique ID for this alert ---@param level string The level for the alert ---@param message string The message for this alert ---@param isTranslationKey boolean Whether the message is a translation key function sendPersistentAlert(key, level, message, isTranslationKey) debugPrint(('Sending persistent alert, key: %s, level: %s, message: %s'):format(key, level, message)) sendMenuMessage('setPersistentAlert', { key = key, level = level, message = message, isTranslationKey = isTranslationKey }) end --- Clear a persistent alert on screen ---@param key string The unique ID passed in sendPersistentAlert for the notification function clearPersistentAlert(key) debugPrint(('Clearing persistent alert, key: %s'):format(key)) sendMenuMessage('clearPersistentAlert', { key = key }) end --- Snackbar message ---@param level string The severity of the message can be 'info', 'error', or 'warning' ---@param message string Message to display with snackbar ---@param isTranslationKey boolean ---@param tOptions table | nil function sendSnackbarMessage(level, message, isTranslationKey, tOptions) debugPrint(('Sending snackbar message, level: %s, message: %s, isTranslationKey: %s'):format(level, message, isTranslationKey)) sendMenuMessage( 'setSnackbarAlert', { level = level, message = message, isTranslationKey = isTranslationKey, tOptions = tOptions } ) end --- Send data to the NUI frame ---@param action string Action ---@param data any Data corresponding to action function sendMenuMessage(action, data) SendNUIMessage({ action = action, data = data }) end --- Close the menu if pause menu is opened using the default P key local function createPauseMenuCheckerThread() debugPrint('Starting pause menu checker thread') CreateThread(function() while isMenuVisible do if IsPauseMenuActive() then toggleMenuVisibility(false) end Wait(250) end end) end --- Toggle visibility of the txAdmin NUI menu function toggleMenuVisibility(visible) if (visible == true and isMenuVisible) or (visible == false and not isMenuVisible) then return end if visible == nil then if not isMenuVisible and IsPauseMenuActive() then return end end sendReactPlayerlist() if visible ~= nil then isMenuVisible = visible sendMenuMessage('setVisible', visible) else isMenuVisible = not isMenuVisible sendMenuMessage('setVisible', isMenuVisible) end createPauseMenuCheckerThread() -- check if noclip and spectate still works with menu closed if not isMenuVisible then SetNuiFocus(false) SetNuiFocusKeepInput(false) tsLastMenuClose = GetGameTimer() end playLibrarySound('enter') end --- Calculate a safe Z coordinate based off the (X, Y) ---@param x number ---@param y number ---@return number|nil function FindZForCoords(x, y) local found = true local START_Z = 1500 local z = START_Z while found and z > 0 do local _found, _z = GetGroundZAndNormalFor_3dCoord(x + 0.0, y + 0.0, z - 1.0) if _found then z = _z + 0.0 end found = _found Wait(0) end if z == START_Z then return nil end return z + 0.0 end --- Display simple help scaleform ---@param msg string - The message to display function DisplayHelpTxtThisFrame(msg) BeginTextCommandDisplayHelp('STRING') AddTextComponentString(msg) AddTextComponentSubstringTextLabel(msg) EndTextCommandDisplayHelp(0, 1, 0, -1); end --- Used for local feedback and permission checks. Checks are still --- performed on the server. ---@param perms table Array of all player permissions ---@param perm string The specific permission ---@return boolean function DoesPlayerHavePerm(perms, perm) if type(perms) ~= 'table' then return false end for _, v in pairs(perms) do if v == perm or v == 'all_permissions' then return true end end return false end -- Sound libraries local fivemSoundLibrary = { move = {'NAV_UP_DOWN', 'HUD_FRONTEND_DEFAULT_SOUNDSET'}, enter = {'SELECT', 'HUD_FRONTEND_DEFAULT_SOUNDSET'}, confirm = {'CONFIRM_BEEP', 'HUD_MINI_GAME_SOUNDSET'}, } local redmSoundLibrary = { move = {'round_start_countdown_tick', 'RDRO_Poker_Sounds'}, enter = {'BET_PROMPT', 'HUD_POKER'}, confirm = {'BULLSEYE', 'FMA_ARCHERY_Sounds'}, } --- Used to play UI sounds ---@param sound string function playLibrarySound(sound) if IS_FIVEM then PlaySoundFrontend(-1, fivemSoundLibrary[sound][1], fivemSoundLibrary[sound][2], 1) else Citizen.InvokeNative(0x9D746964E0CF2C5F, redmSoundLibrary[sound][1], redmSoundLibrary[sound][2]) -- ReleaseShardSounds Wait(0) PlaySoundFrontend(redmSoundLibrary[sound][1], redmSoundLibrary[sound][2], true, 1); end end