Redix LogoDocumentation

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)
end

Session 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)
end

Caching 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)
end

Rate 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)
end

Multi-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)
end

These examples demonstrate common patterns and use cases for Redix in FiveM and RedM servers. Adapt them to your specific needs and framework.

Next Steps