Skip to content

FiveM 示例

本章节提供了 Sleet ORM 在 FiveM 开发中的实际应用示例,涵盖常见的游戏功能模块。

快速开始

所有示例都基于相同的基础 Schema 结构,您可以根据需要进行调整:

lua
-- server/schema.lua
local sl = Sleet

-- 玩家基础表
local players = sl.table('players', {
    id = sl.serial().primaryKey().comment('玩家ID'),
    identifier = sl.varchar(64).notNull().unique().comment('Steam/Discord标识符'),
    name = sl.varchar(255).notNull().comment('玩家名称'),
    money = sl.int().default(5000).comment('现金'),
    bank = sl.int().default(25000).comment('银行存款'),
    level = sl.int().default(1).comment('等级'),
    experience = sl.bigint().default(0).comment('经验值'),
    is_admin = sl.boolean().default(false).comment('管理员'),
    metadata = sl.json().comment('扩展数据'),
    last_seen = sl.timestamp().defaultNow().comment('最后在线'),
    created_at = sl.timestamp().defaultNow().comment('创建时间'),
    updated_at = sl.timestamp().defaultNow().onUpdate(sl.sql('NOW()')).comment('更新时间')
})

-- 商品表
local items = sl.table('items', {
    id = sl.serial().primaryKey(),
    name = sl.varchar(255).notNull().comment('商品名称'),
    label = sl.varchar(255).notNull().comment('显示名称'),
    category = sl.varchar(50).comment('分类'),
    price = sl.decimal(10, 2).comment('价格'),
    weight = sl.decimal(5, 2).default(0.1).comment('重量'),
    is_usable = sl.boolean().default(false).comment('是否可使用'),
    metadata = sl.json().comment('商品属性')
})

-- 玩家物品表
local player_items = sl.table('player_items', {
    id = sl.serial().primaryKey(),
    player_id = sl.int().notNull().references(players.id).comment('玩家ID'),
    item_id = sl.int().notNull().references(items.id).comment('商品ID'),
    quantity = sl.int().default(1).comment('数量'),
    metadata = sl.json().comment('物品数据'),
    created_at = sl.timestamp().defaultNow()
})

return {
    players = players,
    items = items,
    player_items = player_items
}

使用指南

1. 环境设置

确保您的资源包含以下依赖:

lua
-- fxmanifest.lua
fx_version 'cerulean'
game 'gta5'

description '使用 Sleet ORM 的示例系统'

dependencies {
    'oxmysql',
    'sleet'
}

server_scripts {
    '@oxmysql/lib/MySQL.lua',
    '@sleet/sleet.lua',
    'server/schema.lua',
    'server/*.lua'
}

client_scripts {
    'client/*.lua'
}

2. 数据库连接

lua
-- server/main.lua
local sl = Sleet
local s = require 'server.schema'
local db = sl.connect()

-- 测试连接
CreateThread(function()
    local result = db.select().from(s.players).limit(1).execute()
    print('数据库连接成功,玩家表记录数:', #result)
end)

3. 基础操作

lua
-- 创建玩家
function CreatePlayer(identifier, name)
    return db.insert(s.players)
        .values({
            identifier = identifier,
            name = name
        })
        .execute()
end

-- 获取玩家
function GetPlayer(identifier)
    return db.select()
        .from(s.players)
        .where(sl.eq(s.players.identifier, identifier))
        .limit(1)
        .execute()[1]
end

-- 更新玩家金钱
function UpdatePlayerMoney(playerId, money, bank)
    return db.update(s.players)
        .set({
            money = money,
            bank = bank,
            updated_at = sl.sql('NOW()')
        })
        .where(sl.eq(s.players.id, playerId))
        .execute()
end

最佳实践

1. 错误处理

lua
function SafeUpdateMoney(playerId, amount)
    local success, result = pcall(function()
        return db.update(s.players)
            .set({ money = sl.sql('money + ?', { amount }) })
            .where(sl.and_(
                sl.eq(s.players.id, playerId),
                sl.gte(sl.sql('money + ?', { amount }), 0)
            ))
            .execute()
    end)

    if not success then
        print('更新金钱失败:', result)
        return false
    end

    return result > 0
end

2. 性能优化

lua
-- 批量操作
function GiveItemsToPlayers(playerIds, itemId, quantity)
    local values = {}
    for _, playerId in ipairs(playerIds) do
        table.insert(values, {
            player_id = playerId,
            item_id = itemId,
            quantity = quantity
        })
    end

    return db.insert(s.player_items)
        .values(values)
        .execute()
end

-- 索引友好的查询
function GetPlayerByIdentifier(identifier)
    -- identifier 字段应该有唯一索引
    return db.select()
        .from(s.players)
        .where(sl.eq(s.players.identifier, identifier))
        .limit(1)
        .execute()[1]
end

3. 数据验证

lua
function ValidatePlayerData(data)
    if not data.identifier or #data.identifier == 0 then
        return false, '标识符不能为空'
    end

    if not data.name or #data.name < 3 then
        return false, '名称至少需要3个字符'
    end

    if data.money and (data.money < 0 or data.money > 999999999) then
        return false, '金钱数额无效'
    end

    return true
end

调试技巧

查看生成的 SQL

lua
-- 调试模式下打印 SQL
local function debugQuery(queryBuilder)
    local sql, params = queryBuilder.toSQL()
    print('SQL:', sql)
    print('参数:', json.encode(params))
    return queryBuilder.execute()
end

-- 使用示例
local players = debugQuery(
    db.select()
        .from(s.players)
        .where(sl.gte(s.players.level, 10))
)

性能监控

lua
local function timedQuery(name, queryFunc)
    local startTime = GetGameTimer()
    local result = queryFunc()
    local endTime = GetGameTimer()

    print(('查询 %s 耗时: %dms'):format(name, endTime - startTime))
    return result
end

-- 使用示例
local topPlayers = timedQuery('获取排行榜', function()
    return db.select()
        .from(s.players)
        .orderBy(s.players.level, 'desc')
        .limit(10)
        .execute()
end)

下一步

选择一个感兴趣的示例开始学习:

或者直接查看 API 参考 了解更多技术细节。

Released under the MIT License.