User Database & Utility API
Overview
The User Database & Utility API provides comprehensive functions for user management, database operations, and cross-resource communication. This system handles user creation, lookups, ban management, and unique identifier generation, utilizing the Tunnel/Proxy pattern for seamless client-server communication.
Tunnel & Proxy System
The API utilizes a modified vRP-style Tunnel and Proxy system for inter-resource communication:
Tunnel: Provides two-way communication between server and clients with async support
Proxy: Enables function calls between different resources on the same side
Basic Usage
To enable the library inside of your resource just add @frp_lib/library/linker.lua as a shared_script in your fxmanifest.lua file.
shared_scripts {
'@frp_lib/library/linker.lua',
}
Or if the library is the only shared script you use you can do:
shared_script '@frp_lib/library/linker.lua'
-- Import the API using Proxy
local API = Proxy.getInterface("API")
-- Or using Tunnel for client-server communication
local cAPI = Tunnel.getInterface("API")
User Creation & Management
API.CreateUser
Creates a new user account with credentials in the database.
Parameters
playerId
(number): The player's server source IDmappedIdentifiers
(table): Mapped player identifiers containing all platform identifiers
Returns
userId
(number): The newly created user IDnil
: If creation failed
Example
local identifiers = GetPlayerIdentifiers(source)
local mappedIdentifiers = MapIdentifiers(identifiers)
local userId = API.CreateUser(source, mappedIdentifiers)
if userId then
print("User created with ID:", userId)
else
print("Failed to create user")
end
What it does
Creates user record with player name
Stores all platform credentials (Steam, Discord, License, etc.)
Integrates with external systems (prime_api)
Logs user creation for auditing
Database Structure
-- user table
INSERT INTO user (name) VALUES(?)
-- user_credentials table
INSERT INTO user_credentials (
userId, fivem, steam, ip, license, license2,
xbl, live, discord
) VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?)
User Lookup Functions
API.GetUserIdentifiersByIdentifier
Retrieves all identifiers for a user by a specific identifier.
Parameters
identifier
(string): The identifier value to search foridentifierKey
(string): The type of identifier ("steam", "discord", "license", etc.)
Returns
credentials
(table): Complete user credentials recordnil
: If no user found
Example
local userCredentials = API.GetUserIdentifiersByIdentifier("steam:110000123456789", "steam")
if userCredentials then
print("User ID:", userCredentials.userId)
print("Discord:", userCredentials.discord)
print("License:", userCredentials.license)
end
API.GetUserIdByIdentifier
Gets a user ID by a specific identifier.
Parameters
identifier
(string): The identifier value to search foridentifierKey
(string): The type of identifier
Returns
userId
(number): The user's database IDnil
: If no user found
Example
local userId = API.GetUserIdByIdentifier("discord:123456789012345678", "discord")
if userId then
print("Found user ID:", userId)
else
print("User not found")
end
API.GetUserIdByIdentifiers
Gets a user ID using the primary identifier from a list of identifiers.
Parameters
identifiers
(table): Array of player identifiersname
(string): Player name (currently unused)
Returns
userId
(number): The user's database IDnil
: If no user found
Example
local identifiers = GetPlayerIdentifiers(source)
local userId = API.GetUserIdByIdentifiers(identifiers, GetPlayerName(source))
if userId then
print("Existing user found:", userId)
else
print("New user - needs to be created")
end
Character & User Data Retrieval
API.GetCharacterFromCitizenIdOffline
Retrieves character data by citizen ID from the database (offline lookup).
Parameters
citizenId
(string): The character's citizen ID
Returns
character
(table): Complete character database recordnil
: If character not found
Example
local character = API.GetCharacterFromCitizenIdOffline("A1234")
if character then
print("Character:", character.firstName, character.lastName)
print("User ID:", character.userId)
print("Birth Date:", character.birthDate)
end
API.GetCharacterFromCharId
Retrieves character data by character ID from the database.
Parameters
charId
(number): The character's database ID
Returns
character
(table): Complete character database recordnil
: If character not found
Example
local character = API.GetCharacterFromCharId(456)
if character then
print("Character found:", character.citizenId)
end
API.GetUserFromUserIdOffline
Retrieves user data by user ID from the database (offline lookup).
Parameters
userId
(number): The user's database ID
Returns
user
(table): Complete user database recordnil
: If user not found
Example
local userData = API.GetUserFromUserIdOffline(123)
if userData then
print("User name:", userData.name)
print("Character slots:", userData.numCharSlots)
print("Created at:", userData.createdAt)
end
API.GetUserCharactersOffline
Retrieves all characters for a user (offline lookup).
Parameters
userId
(number): The user's database ID
Returns
characters
(table): Array of character records{}
: Empty array if no characters found
Example
local characters = API.GetUserCharactersOffline(123)
print("User has", #characters, "characters:")
for i, char in ipairs(characters) do
print("Character", i, ":", char.firstName, char.lastName, "(" .. char.citizenId .. ")")
end
Active User Management
API.GetUserFromUserId
Gets an active user object by user ID.
Parameters
userId
(number): The user's database ID
Returns
User
(table): The active user objectnil
: If user is not online
Example
local user = API.GetUserFromUserId(123)
if user then
print("User is online:", user:GetName())
user:Notify("info", "Admin message!")
else
print("User is not online")
end
API.GetUserIdFromServerId
Gets a user ID from a server source ID.
Parameters
source
(number): The player's server source ID
Returns
userId
(number): The user's database IDnil
: If user not found
Example
local userId = API.GetUserIdFromServerId(source)
if userId then
print("Player source", source, "is user ID", userId)
end
API.GetUserFromSource
Gets an active user object by server source ID.
Parameters
source
(number): The player's server source ID
Returns
User
(table): The active user objectnil
: If user not found
Example
-- Common usage in commands
RegisterCommand("balance", function(source, args)
local user = API.GetUserFromSource(source)
if not user then
return
end
local character = user:GetCharacter()
if character then
local balance = character:GetBankBalance()
user:Notify("info", "Balance: $" .. balance)
end
end)
API.GetUserFromCharId
Gets an active user object by character ID.
Parameters
charId
(number): The character's database ID
Returns
User
(table): The active user objectnil
: If user not online or character not found
Example
local user = API.GetUserFromCharId(789)
if user then
print("Character owner is online:", user:GetName())
end
API.GetUserFromCitizenId
Gets an active user object by citizen ID.
Parameters
citizenId
(string): The character's citizen ID
Returns
User
(table): The active user objectnil
: If user not online or character not found
Example
local user = API.GetUserFromCitizenId("A1234")
if user then
local character = user:GetCharacter()
print("Character is online:", character:GetFullName())
end
API.GetUserFromDiscordId
Gets an active user object by Discord ID.
Parameters
discordId
(string): The user's Discord ID (without "discord:" prefix)
Returns
User
(table): The active user objectnil
: If user not online
Example
local discordId = "123456789012345678"
local user = API.GetUserFromDiscordId(discordId)
if user then
print("Discord user is online as:", user:GetName())
user:Notify("info", "You have a Discord message!")
end
API.GetUserIdFromCharId
Gets a user ID from a character ID (with fallback to database).
Parameters
charId
(number): The character's database ID
Returns
userId
(number): The user's database IDnil
: If character not found
Example
local userId = API.GetUserIdFromCharId(456)
if userId then
print("Character 456 belongs to user:", userId)
end
API.GetUsers
Gets all currently active user objects.
Returns
users
(table): Table of all active users indexed by user ID
Example
local allUsers = API.GetUsers()
local userCount = 0
for userId, user in pairs(allUsers) do
userCount = userCount + 1
print("User", userId, ":", user:GetName())
end
print("Total online users:", userCount)
Ban Management System
API.SetBanned
Bans a user and kicks them from the server.
Parameters
source
(number): The player's server source ID (for kicking)userId
(number): The user's database ID to banreason
(string): Reason for the ban
Returns
None
Example
RegisterCommand("ban", function(source, args)
if not CheckAdminPermission(source) then return end
local targetId = tonumber(args[1])
local reason = table.concat(args, " ", 2) or "No reason provided"
local targetUser = API.GetUserFromSource(targetId)
if targetUser then
API.SetBanned(targetId, targetUser:GetId(), reason)
print("Banned user:", targetUser:GetName(), "Reason:", reason)
end
end)
API.UnBan
Removes a ban from a user account.
Parameters
source
(number): Command source (not used currently)userId
(number): The user's database ID to unban
Returns
None
Example
RegisterCommand("unban", function(source, args)
if not CheckAdminPermission(source) then return end
local userId = tonumber(args[1])
if userId then
API.UnBan(source, userId)
print("Unbanned user ID:", userId)
end
end)
API.IsBanned
Checks if a user is currently banned.
Parameters
userId
(number): The user's database ID to check
Returns
banned
(boolean): True if user is banned, false otherwise
Example
-- Check during connection
AddEventHandler('playerConnecting', function(name, setKickReason)
local source = source
local identifiers = GetPlayerIdentifiers(source)
local userId = API.GetUserIdByIdentifiers(identifiers, name)
if userId and API.IsBanned(userId) then
setKickReason("You are banned from this server")
CancelEvent()
end
end)
Cache Management
API.ClearUserFromCache
Removes a user from all caches and tracking tables.
Parameters
source
(number): The player's server source IDuserId
(number): The user's database ID
Returns
None
Example
-- Automatic cleanup when player disconnects
AddEventHandler('playerDropped', function(reason)
local source = source
local user = API.GetUserFromSource(source)
if user then
API.ClearUserFromCache(source, user:GetId())
print("Cleaned up user cache for:", user:GetName())
end
end)
Console Command
clearUser <userId>
Clears a specific user from cache (console only).
Unique ID Generation
API.CreateCitizenId
Generates a unique citizen ID for new characters.
Returns
citizenId
(string): A unique citizen ID (format: A1234)
Example
local citizenId = API.CreateCitizenId()
print("Generated citizen ID:", citizenId) -- Example: "A1234"
Algorithm
Combines random string (1 char) + random number (4 digits)
Ensures uniqueness by checking against existing characters
Uppercase format for consistency
API.GenerateCharFingerPrint
Generates a unique fingerprint for new characters.
Returns
fingerprint
(string): A unique fingerprint string
Example
local fingerprint = API.GenerateCharFingerPrint()
print("Generated fingerprint:", fingerprint) -- Example: "AB123C45DEF6789"
Algorithm
Complex pattern: String(2) + Number(3) + String(1) + Number(2) + String(3) + Number(4)
Stored in character metadata as JSON
Ensures uniqueness against existing character fingerprints
Usage Examples
Complete User Connection Flow
AddEventHandler('playerConnecting', function(name, setKickReason, deferrals)
local source = source
local identifiers = GetPlayerIdentifiers(source)
deferrals.defer()
deferrals.update("Checking user data...")
-- Check if user exists
local userId = API.GetUserIdByIdentifiers(identifiers, name)
if not userId then
-- Create new user
deferrals.update("Creating new user...")
local mappedIdentifiers = MapIdentifiers(identifiers)
userId = API.CreateUser(source, mappedIdentifiers)
if not userId then
deferrals.done("Failed to create user account")
return
end
else
-- Check if banned
if API.IsBanned(userId) then
deferrals.done("You are banned from this server")
return
end
end
deferrals.done()
end)
Admin User Management Commands
RegisterCommand("userinfo", function(source, args)
if not CheckAdminPermission(source) then return end
local targetId = tonumber(args[1])
if not targetId then return end
-- Try to get online user first
local user = API.GetUserFromSource(targetId)
if user then
print("=== ONLINE USER INFO ===")
print("Name:", user:GetName())
print("User ID:", user:GetId())
print("Character ID:", user:GetCharacterId())
print("IP:", user:GetIpAddress())
return
end
-- Get offline data
local userId = API.GetUserIdFromServerId(targetId)
if userId then
local userData = API.GetUserFromUserIdOffline(userId)
if userData then
print("=== OFFLINE USER INFO ===")
print("Name:", userData.name)
print("User ID:", userData.id)
print("Created:", userData.createdAt)
end
end
end)
RegisterCommand("finduser", function(source, args)
if not CheckAdminPermission(source) then return end
local searchType = args[1] -- "steam", "discord", "citizen"
local searchValue = args[2]
if not searchType or not searchValue then
print("Usage: finduser <type> <value>")
print("Types: steam, discord, citizen, char")
return
end
local user = nil
if searchType == "steam" then
user = API.GetUserFromSource(API.GetUserIdByIdentifier(searchValue, "steam"))
elseif searchType == "discord" then
local discordId = searchValue:gsub("discord:", "")
user = API.GetUserFromDiscordId(discordId)
elseif searchType == "citizen" then
user = API.GetUserFromCitizenId(searchValue)
elseif searchType == "char" then
local charId = tonumber(searchValue)
user = API.GetUserFromCharId(charId)
end
if user then
print("Found user:", user:GetName(), "ID:", user:GetId())
else
print("User not found or not online")
end
end)
Character Management Integration
-- When creating a character
function CreateCharacter(source, characterData)
local user = API.GetUserFromSource(source)
if not user then return false end
-- Generate unique IDs
local citizenId = API.CreateCitizenId()
local fingerprint = API.GenerateCharFingerPrint()
-- Add to metadata
characterData.metadata = characterData.metadata or {}
characterData.metadata.fingerprint = fingerprint
-- Create character with unique citizen ID
local charId = user:CreateCharacter(
characterData.firstName,
characterData.lastName,
characterData.birthDate,
characterData.appearance,
characterData.clothing,
characterData.metadata
)
return charId
end
-- Cross-character messaging
RegisterCommand("message", function(source, args)
local user = API.GetUserFromSource(source)
if not user then return end
local targetCitizenId = args[1]
local message = table.concat(args, " ", 2)
local targetUser = API.GetUserFromCitizenId(targetCitizenId)
if targetUser then
targetUser:Notify("info", "Message from " .. user:GetCharacter():GetFullName() .. ": " .. message)
user:Notify("success", "Message sent to " .. targetCitizenId)
else
user:Notify("error", "Character not found or not online")
end
end)
Ban Management System
RegisterCommand("ban", function(source, args)
if not CheckAdminPermission(source) then return end
local targetId = tonumber(args[1])
local reason = table.concat(args, " ", 2) or "Violation of server rules"
local targetUser = API.GetUserFromSource(targetId)
if targetUser then
local userId = targetUser:GetId()
local userName = targetUser:GetName()
API.SetBanned(targetId, userId, reason)
-- Log the ban
local adminUser = API.GetUserFromSource(source)
local adminName = adminUser and adminUser:GetName() or "Console"
print(("BAN: %s (ID: %s) banned %s (ID: %s) - Reason: %s"):format(
adminName, source, userName, userId, reason
))
-- Notify other admins
local allUsers = API.GetUsers()
for _, user in pairs(allUsers) do
if user:HasGroup("admin") then
user:Notify("warning", userName .. " was banned by " .. adminName)
end
end
else
print("Target player not found")
end
end)
RegisterCommand("checkban", function(source, args)
if not CheckAdminPermission(source) then return end
local targetId = tonumber(args[1])
-- Try multiple methods to find user ID
local userId = nil
-- Method 1: Online player
local targetUser = API.GetUserFromSource(targetId)
if targetUser then
userId = targetUser:GetId()
else
-- Method 2: Use server ID to get user ID
userId = API.GetUserIdFromServerId(targetId)
end
if userId then
local isBanned = API.IsBanned(userId)
print("User ID", userId, "ban status:", isBanned and "BANNED" or "NOT BANNED")
else
print("Could not find user ID for target:", targetId)
end
end)
Performance Monitoring
-- Monitor cache sizes
RegisterCommand("cachestats", function(source, args)
if source ~= 0 then return end -- Console only
local allUsers = API.GetUsers()
local activeUsers = 0
local loggedInUsers = 0
for userId, user in pairs(allUsers) do
activeUsers = activeUsers + 1
if user:GetCharacter() then
loggedInUsers = loggedInUsers + 1
end
end
print("=== CACHE STATISTICS ===")
print("Active Users:", activeUsers)
print("Logged In Users:", loggedInUsers)
print("Memory Usage: ~" .. (activeUsers * 50) .. "KB estimated")
end)
-- Cleanup disconnected users
CreateThread(function()
while true do
Wait(300000) -- 5 minutes
local allUsers = API.GetUsers()
local cleanupCount = 0
for userId, user in pairs(allUsers) do
local source = user:GetSource()
if GetPlayerName(source) == nil then
-- Player disconnected but not cleaned up
API.ClearUserFromCache(source, userId)
cleanupCount = cleanupCount + 1
end
end
if cleanupCount > 0 then
print("Cleaned up", cleanupCount, "disconnected users from cache")
end
end
end)
Tunnel/Proxy Integration Examples
Server-Side API Export
-- In your main server file
local API = {}
-- Define all your API functions here...
-- Export via Proxy for other server resources
Proxy.addInterface("frp_core", API)
-- Export via Tunnel for client communication
Tunnel.bindInterface("frp_core", API)
Client-Side Usage
-- Client-side script accessing server API
local Tunnel = module("lib/Tunnel")
local API = Tunnel.getInterface("frp_core", "your_resource_name")
-- Now you can call server functions from client
RegisterCommand("mybalance", function()
local userId = API.GetUserIdFromServerId(GetPlayerServerId(PlayerId()))
if userId then
-- This calls the server and waits for response
print("My user ID is:", userId)
end
end)
Cross-Resource Server Usage
-- In another server resource
local Proxy = module("lib/Proxy")
local API = Proxy.getInterface("frp_core", GetCurrentResourceName())
-- Use API functions from another resource
RegisterCommand("getuser", function(source, args)
local user = API.GetUserFromSource(source)
if user then
print("Found user:", user.GetName()) -- Note: Proxy calls return values directly
end
end)
Best Practices
Error Handling
function SafeUserLookup(source)
local success, user = pcall(API.GetUserFromSource, source)
if not success then
print("Error getting user for source", source, ":", user)
return nil
end
return user
end
Performance Optimization
-- Cache frequently accessed data
local userIdCache = {}
function GetCachedUserId(source)
if userIdCache[source] then
return userIdCache[source]
end
local userId = API.GetUserIdFromServerId(source)
if userId then
userIdCache[source] = userId
-- Clear cache when player disconnects
local cleanup = function()
userIdCache[source] = nil
end
-- Set cleanup timer
SetTimeout(600000, cleanup) -- 10 minutes
end
return userId
end
Database Safety
function SafeDatabaseOperation(operation, ...)
local success, result = pcall(operation, ...)
if not success then
print("Database operation failed:", result)
return nil
end
return result
end
-- Usage
local user = SafeDatabaseOperation(API.GetUserFromUserIdOffline, 123)
Security Considerations
Input Validation: Always validate user inputs before database queries
Rate Limiting: Implement rate limits for user creation and lookups
Permission Checks: Verify permissions before sensitive operations
Audit Logging: Log all user management operations
Cache Management: Regularly clean up disconnected users from memory
This comprehensive API provides robust user management capabilities with efficient caching, cross-resource communication, and database safety features.
Last updated