Examples
Practical examples of using Redix in FiveM and RedM servers
Getting Started
All examples assume you have already obtained the Redix interface:
local Redix = exports.redix:GetInterface()Character Data Management
Saving Character Appearance
Store complex JSON character appearance data efficiently:
function SaveCharacterAppearance(playerId, appearanceData)
local key = 'character:' .. playerId .. ':appearance'
Redix.JSONSet(key, '$', appearanceData, function(err, result)
if not err then
print('Character appearance saved for player ' .. playerId)
else
print('Error saving appearance:', err)
end
end)
end
-- Usage
local appearance = {
face = 1,
hair = 5,
hairColor = 2,
eyeColor = 1,
tattoos = {
{zone = 'head', id = 1},
{zone = 'torso', id = 5}
},
clothing = {
hat = {drawable = 1, texture = 0},
shirt = {drawable = 15, texture = 2},
pants = {drawable = 10, texture = 1}
}
}
SaveCharacterAppearance(source, appearance)Loading Character Data
function LoadCharacterData(playerId, callback)
local profileKey = 'character:' .. playerId .. ':profile'
local appearanceKey = 'character:' .. playerId .. ':appearance'
-- Load profile
Redix.HGetAll(profileKey, function(err, profile)
if err then
callback(nil)
return
end
-- Load appearance
Redix.JSONGet(appearanceKey, '$', function(err, appearance)
if err then
callback(profile)
return
end
-- Combine data
profile.appearance = appearance
callback(profile)
end)
end)
end
-- Usage
LoadCharacterData(source, function(data)
if data then
print('Loaded character:', data.name, 'Level:', data.level)
-- Apply appearance, spawn player, etc.
else
print('Failed to load character data')
end
end)Inventory System
Basic Inventory Operations
-- Add item to inventory
function AddItem(playerId, itemName, quantity)
local key = 'inventory:' .. playerId
local itemPath = '$.items.' .. itemName
-- Check if item exists
Redix.JSONGet(key, itemPath, function(err, currentQty)
if err or not currentQty then
-- Create new item entry
Redix.JSONSet(key, itemPath, {quantity = quantity, addedAt = os.time()})
else
-- Increment existing quantity
Redix.JSONNumIncrBy(key, itemPath .. '.quantity', quantity)
end
end)
end
-- Remove item from inventory
function RemoveItem(playerId, itemName, quantity)
local key = 'inventory:' .. playerId
local itemPath = '$.items.' .. itemName .. '.quantity'
Redix.JSONGet(key, itemPath, function(err, currentQty)
if err or not currentQty or currentQty < quantity then
print('Insufficient items')
return false
end
-- Decrement quantity
Redix.JSONNumIncrBy(key, itemPath, -quantity, function(err, newQty)
if newQty <= 0 then
-- Remove item if quantity is 0
Redix.JSONDel(key, '$.items.' .. itemName)
end
end)
return true
end)
end
-- Get full inventory
function GetInventory(playerId, callback)
local key = 'inventory:' .. playerId
Redix.JSONGet(key, '$', callback)
end
-- Usage
AddItem(source, 'bread', 5)
RemoveItem(source, 'bread', 2)
GetInventory(source, function(err, inventory)
print('Inventory:', json.encode(inventory))
end)Leaderboard System
Player Ranking
-- Update player score
function UpdatePlayerScore(playerId, score)
local playerName = GetPlayerName(playerId)
Redix.ZAdd('leaderboard:global', score, playerName)
end
-- Get top 10 players
function GetTopPlayers(callback)
Redix.ZRevRange('leaderboard:global', 0, 9, 'WITHSCORES', function(err, results)
if not err and results then
local leaderboard = {}
for i = 1, #results, 2 do
table.insert(leaderboard, {
name = results[i],
score = tonumber(results[i + 1])
})
end
callback(leaderboard)
end
end)
end
-- Get player rank
function GetPlayerRank(playerId, callback)
local playerName = GetPlayerName(playerId)
Redix.ZRevRank('leaderboard:global', playerName, function(err, rank)
if not err and rank then
callback(rank + 1) -- Rank is 0-indexed
else
callback(nil)
end
end)
end
-- Usage
UpdatePlayerScore(source, 1500)
GetTopPlayers(function(leaderboard)
for i, player in ipairs(leaderboard) do
print(i .. '. ' .. player.name .. ' - ' .. player.score)
end
end)Multiple Leaderboards
-- Create specialized leaderboards
function UpdateLeaderboards(playerId)
local stats = GetPlayerStats(playerId)
local playerName = GetPlayerName(playerId)
-- Overall level leaderboard
Redix.ZAdd('leaderboard:level', stats.level, playerName)
-- Kills leaderboard
Redix.ZAdd('leaderboard:kills', stats.kills, playerName)
-- Money leaderboard
Redix.ZAdd('leaderboard:money', stats.money, playerName)
-- Playtime leaderboard
Redix.ZAdd('leaderboard:playtime', stats.playtime, playerName)
end
-- Get leaderboard by type
function GetLeaderboard(type, limit, callback)
local key = 'leaderboard:' .. type
Redix.ZRevRange(key, 0, limit - 1, 'WITHSCORES', function(err, results)
if not err and results then
local leaderboard = {}
for i = 1, #results, 2 do
table.insert(leaderboard, {
name = results[i],
value = tonumber(results[i + 1])
})
end
callback(leaderboard)
end
end)
endSession Management
Player Sessions
-- Create session on player connect
function CreatePlayerSession(playerId)
local sessionKey = 'session:' .. playerId
local sessionData = {
playerId = playerId,
joinTime = os.time(),
lastActivity = os.time(),
ip = GetPlayerEndpoint(playerId)
}
-- Session expires in 2 hours
Redix.Save(sessionKey, sessionData, 7200)
end
-- Update session activity
function UpdateSessionActivity(playerId)
local sessionKey = 'session:' .. playerId
Redix.Get(sessionKey, function(err, session)
if not err and session then
session.lastActivity = os.time()
Redix.Save(sessionKey, session, 7200)
end
end)
end
-- Get active sessions
function GetActiveSessions(callback)
Redix.GetKeys('session:*', function(err, keys)
if not err and keys then
Redix.GetMultiple(keys, callback)
end
end)
end
-- Clean up session on disconnect
function CleanupSession(playerId)
local sessionKey = 'session:' .. playerId
Redix.Invalidate(sessionKey)
endCaching System
Query Caching
-- Cache expensive database queries
function GetPlayerDataWithCache(playerId, callback)
local cacheKey = 'cache:player:' .. playerId
-- Try to get from cache first
Redix.Get(cacheKey, function(err, cachedData)
if not err and cachedData then
print('Cache hit for player ' .. playerId)
callback(cachedData)
return
end
-- Cache miss, query database
print('Cache miss for player ' .. playerId)
MySQL.Async.fetchAll('SELECT * FROM players WHERE id = @id', {
['@id'] = playerId
}, function(result)
if result[1] then
-- Cache for 5 minutes
Redix.Save(cacheKey, result[1], 300)
callback(result[1])
else
callback(nil)
end
end)
end)
end
-- Invalidate cache when data changes
function UpdatePlayerData(playerId, newData)
-- Update database
MySQL.Async.execute('UPDATE players SET ... WHERE id = @id', {
['@id'] = playerId
}, function(affectedRows)
if affectedRows > 0 then
-- Invalidate cache
Redix.Invalidate('cache:player:' .. playerId)
end
end)
endRate Limiting
API Rate Limiting
function CheckRateLimit(playerId, action, maxRequests, timeWindow)
local key = 'ratelimit:' .. playerId .. ':' .. action
Redix.Get(key, function(err, count)
if err then
return false
end
if not count then
-- First request
Redix.Save(key, 1, timeWindow)
return true
elseif count < maxRequests then
-- Under limit
Redix.Increment(key)
return true
else
-- Over limit
Redix.TTL(key, function(err, ttl)
print('Rate limit exceeded. Try again in ' .. ttl .. ' seconds')
end)
return false
end
end)
end
-- Usage
RegisterCommand('withdraw', function(source, args)
-- Allow 5 withdrawals per 60 seconds
if CheckRateLimit(source, 'withdraw', 5, 60) then
-- Process withdrawal
print('Processing withdrawal for player ' .. source)
else
print('Rate limit exceeded for player ' .. source)
end
end)Pub/Sub Communication
Cross-Resource Events
-- Resource A: Subscribe to events
Redix.Subscribe('player:events', function(message)
local data = json.decode(message)
if data.event == 'moneyChanged' then
TriggerClientEvent('updateMoney', data.playerId, data.newAmount)
elseif data.event == 'levelUp' then
TriggerClientEvent('showLevelUp', data.playerId, data.newLevel)
end
end)
-- Resource B: Publish events
function OnMoneyChanged(playerId, newAmount)
local message = json.encode({
event = 'moneyChanged',
playerId = playerId,
newAmount = newAmount,
timestamp = os.time()
})
Redix.Publish('player:events', message)
end
function OnLevelUp(playerId, newLevel)
local message = json.encode({
event = 'levelUp',
playerId = playerId,
newLevel = newLevel,
timestamp = os.time()
})
Redix.Publish('player:events', message)
endMulti-Server Synchronization
-- Server 1: Publish global announcement
function SendGlobalAnnouncement(message)
local data = json.encode({
type = 'announcement',
message = message,
server = GetConvar('serverName', 'Unknown'),
timestamp = os.time()
})
Redix.Publish('global:messages', data)
end
-- All servers: Subscribe to global messages
Redix.Subscribe('global:messages', function(message)
local data = json.decode(message)
if data.type == 'announcement' then
TriggerClientEvent('chat:addMessage', -1, {
template = '<div><b>[{0}]</b> {1}</div>',
args = {data.server, data.message}
})
end
end)Daily Reset System
-- Track daily activities
function IncrementDailyActivity(playerId, activity)
local date = os.date('%Y-%m-%d')
local key = 'daily:' .. date .. ':' .. playerId .. ':' .. activity
Redix.Get(key, function(err, count)
if not count then
-- First time today, expires at midnight
local midnight = os.time({
year = os.date('%Y'),
month = os.date('%m'),
day = os.date('%d') + 1,
hour = 0,
min = 0,
sec = 0
})
local ttl = midnight - os.time()
Redix.Save(key, 1, ttl)
else
Redix.Increment(key)
end
end)
end
-- Check daily limit
function HasReachedDailyLimit(playerId, activity, maxCount, callback)
local date = os.date('%Y-%m-%d')
local key = 'daily:' .. date .. ':' .. playerId .. ':' .. activity
Redix.Get(key, function(err, count)
callback(count and count >= maxCount)
end)
end
-- Usage
RegisterCommand('dailyreward', function(source)
HasReachedDailyLimit(source, 'reward', 1, function(reached)
if reached then
print('You have already claimed your daily reward')
else
IncrementDailyActivity(source, 'reward')
GivePlayerReward(source)
end
end)
end)Gang Territory System
-- Claim territory
function ClaimTerritory(gangId, territoryId)
local key = 'territory:' .. territoryId
Redix.HSetMultiple(key, {
owner = gangId,
claimedAt = os.time(),
level = 1,
income = 1000
})
-- Add to gang's territories set
Redix.SAdd('gang:' .. gangId .. ':territories', territoryId)
-- Update leaderboard
Redix.ZAdd('leaderboard:gang:territories', 1, gangId)
end
-- Get gang territories
function GetGangTerritories(gangId, callback)
Redix.SMembers('gang:' .. gangId .. ':territories', function(err, territories)
if not err and territories then
callback(territories)
end
end)
end
-- Get territory details
function GetTerritoryDetails(territoryId, callback)
Redix.HGetAll('territory:' .. territoryId, callback)
end
-- Contest territory
function IsContested(territoryId, callback)
local key = 'territory:' .. territoryId .. ':contested'
Redix.Exists(key, callback)
endThese examples demonstrate common patterns and use cases for Redix in FiveM and RedM servers. Adapt them to your specific needs and framework.