Bỏ qua

Truy vấn SQL

API SQL cho phép bạn truy vấn cơ sở dữ liệu trò chơi trực tiếp từ kịch bản Lua sử dụng kết nối ODBC.

Lấy kết nối

local db = GetConnection("GameDB")
db:Connect("MuOnline_GameDB", "sa", "your_password")

Tip

Các kết nối được lưu bộ nhớ đệm theo tên. Gọi GetConnection("GameDB") lần thứ hai sẽ trả về cùng một instance — không cần kết nối lại.

Đọc dữ liệu người chơi

local function GetPlayerResets(playerName)
    local db = GetConnection("GameDB")
    db:ExecQuery("SELECT Reset, MasterReset FROM Character WHERE Name = '" .. playerName .. "'")

    if db:Fetch() then
        local resets = db:GetAsInteger("Reset")
        local masterResets = db:GetAsInteger("MasterReset")
        db:Close()
        return resets, masterResets
    end

    db:Close()
    return 0, 0
end

-- Sử dụng trong bộ xử lý lệnh
BridgeFunctionAttach("OnCommandManager", function(aIndex, code, arg)
    if code == 200 then
        local player = GetUser(aIndex)
        if player == nil then return 0 end

        local resets, mr = GetPlayerResets(player.Name)
        GCNoticeSend(aIndex, 1, "Resets: " .. resets .. " | Master Resets: " .. mr)
        return 1
    end
    return 0
end)

Bảng xếp hạng người chơi trực tuyến

local function ShowTopPlayers(aIndex)
    local db = GetConnection("GameDB")
    db:ExecQuery("SELECT TOP 5 Name, Reset, MasterReset FROM Character ORDER BY MasterReset DESC, Reset DESC")

    GCNoticeSend(aIndex, 1, "--- Top 5 Players ---")
    local rank = 1

    while db:Fetch() do
        local name = db:GetAsString("Name")
        local resets = db:GetAsInteger("Reset")
        local mr = db:GetAsInteger("MasterReset")

        GCNoticeSend(aIndex, 1, "#" .. rank .. " " .. name .. " - MR:" .. mr .. " R:" .. resets)
        rank = rank + 1
    end

    db:Close()
end

Ghi dữ liệu

local function SaveCustomData(playerName, eventScore)
    local db = GetConnection("GameDB")

    local query = string.format(
        "IF EXISTS (SELECT 1 FROM CustomEventScores WHERE Name = '%s') "..
        "UPDATE CustomEventScores SET Score = %d WHERE Name = '%s' "..
        "ELSE INSERT INTO CustomEventScores (Name, Score) VALUES ('%s', %d)",
        playerName, eventScore, playerName, playerName, eventScore
    )

    db:ExecQuery(query)
    db:Close()
end

SQL Injection

Các ví dụ trên sử dụng nối chuỗi cho đơn giản. Trong môi trường thực tế, hãy sử dụng BindParameterAsString cho dữ liệu đầu vào từ người dùng để ngăn chặn SQL injection.

Sử dụng truy vấn có tham số

local function SafeGetPlayer(playerName)
    local db = GetConnection("GameDB")

    db:BindParameterAsString(1, playerName)
    db:ExecQuery("SELECT Reset FROM Character WHERE Name = ?")

    local resets = 0
    if db:Fetch() then
        resets = db:GetAsInteger("Reset")
    end

    db:Close()
    return resets
end

Tham khảo các phương thức QueryManager

Phương thức Mô tả
Connect(dsn, user, pass) Mở kết nối ODBC
ExecQuery(sql) Thực thi truy vấn SQL
Fetch() Lấy hàng kết quả tiếp theo (true/false)
Close() Đóng truy vấn hiện tại
GetAsInteger(col) Đọc cột số nguyên
GetAsFloat(col) Đọc cột số thực
GetAsInteger64(col) Đọc số nguyên 64-bit
GetAsString(col) Đọc cột chuỗi
GetAsBinary(col) Đọc dữ liệu nhị phân
BindParameterAsString(n, val) Ràng buộc tham số chuỗi
BindParameterAsBinary(n, val) Ràng buộc tham số nhị phân