Skip to content

Server và client ​

Mỗi game KHIM chạy ở hai nơi cùng lúc:

  • Server - mỗi phiên game một server, do KHIM chạy. Các Script của nó nắm game: world, máu, xu, điểm.
  • Thiết bị của từng người chơi - app KHIM hoặc trình duyệt. Các ClientScript lo phím bấm, UI, camera và hiệu ứng của người chơi đó.

Ai thấy gì ​

Script trên serverClientScript
Thay đổi một partTới mọi người chơiChỉ trên màn hình người chơi đó
players.me, input, camera, gui của người chơi-Có
data (lưu), chat.send, achievements, destructionCó-
ServerService và StorageServiceCóKhông bao giờ: chúng không được gửi đi

Vì vậy một cánh cửa do ClientScript mở chỉ mở với một người - và vì server nắm va chạm, người đó vẫn đâm vào nó. Những gì quan trọng phải xảy ra trong Script.

Quy tắc duy nhất

Server quyết định. ClientScript có thể xin, nhưng người chơi có thể chạy app đã bị sửa và gửi bất cứ thứ gì. Script không bao giờ được lấy số lượng, giá tiền, mục tiêu hay kết quả từ người chơi. Nó kiểm tra người chơi có được làm việc đó bây giờ không - đủ gần, còn sống, hết thời gian hồi, đủ tiền - và tự tính con số.

Tin nhắn: net ​

net gửi tin nhắn theo tên giữa server và người chơi. Giá trị có thể là nil, boolean, số, chuỗi, kiểu giá trị (vec3, màu...), part, người chơi và bảng chứa những thứ đó - tối đa 16 KB.

Người chơi gửi server ​

lua
-- ClientScript: xin mua một thanh kiếm
net.send("buy", "Sword")
lua
-- Script: quyết định
local PRICES = {Sword = 50, Shield = 30}

net.on("buy", function(player, item)       -- người gửi đứng đầu
    local price = PRICES[item]
    if not price then return end            -- không phải món ta bán
    if player.stats.Coins < price then return end
    player.stats.Coins -= price
    shared.Items[item]:clone().parent = player.backpack
end)

Server gửi người chơi ​

lua
-- Script
net.send(player, "coinCollected", player.stats.Coins)   -- một người
net.sendAll("roundStarted", 2)                          -- mọi người
lua
-- ClientScript
net.on("coinCollected", function(total)
    label.text = "Xu: " .. total
end)

Hỏi và chờ câu trả lời ​

net.call gửi câu hỏi từ ClientScript và chờ server trả lời; net.handle trả lời nó:

lua
-- Script
net.handle("redeem", function(player, code)
    if code == "WELCOME" and not player.stats.Redeemed then
        player.stats.Coins += 100
        player.stats.Redeemed = true
        return true, "Đã cộng 100 xu!"
    end
    return false, "Mã này không dùng được."
end)
lua
-- ClientScript
local ok, message = net.call("redeem", box.text)
resultLabel.text = message

Lỗi trong hàm xử lý trở thành lỗi ở phía gọi.

Giới hạn ​

Một người chơi gửi tối đa 120 tin nhắn mỗi giây; server bỏ phần còn lại. Một số là NaN hoặc vô cực sẽ khiến cả tin nhắn bị từ chối, và part từ ServerService hay StorageService tới nơi thành nil. Dù vậy - hãy kiểm tra mọi thứ một tin nhắn nói.

Ví dụ: một thanh kiếm ​

lua
-- Script (ServerService): client xin, server quyết
local lastSwing = {}

net.on("swing", function(player)
    local now = time()
    if (lastSwing[player.name] or 0) + 0.5 > now or player.health <= 0 then return end
    lastSwing[player.name] = now

    for _, other in players.all() do
        if other.name ~= player.name and (other.position - player.position).magnitude < 6 then
            other:damage(20)               -- con số của server, không phải của client
        end
    end
end)
lua
-- ClientScript: chỉ gửi cú bấm, không gì khác
input.onKey("F", function()
    net.send("swing")
end)

Client không gửi sát thương, không gửi mục tiêu: server biết mọi người đang ở đâu.

Đặt script ở đâu ​

Mục chứaAi cóĐặt vào đây
WorldServer và mọi người chơiPart, và Script thuộc về một part
ReplicationService (shared)Server và mọi người chơiModel để clone, Module cả hai phía dùng
ServerServiceChỉ serverScript logic game, Module bí mật
ClientServiceMọi người chơiClientScript không gắn với UI
StorageServiceChỉ server, không gì chạyModel và Module cho Script của server
UIMọi người chơiCanvas và ClientScript điều khiển chúng

ClientScript không bí mật

Người chơi nhận mọi ClientScript và mọi Module mà chúng require được (đã bỏ chú thích). Giữ bí mật - mã code, danh sách admin, giá bạn kiểm tra - trong ServerService hoặc StorageService.

Đang ở phía nào ​

lua
if game.isServer then print("server") end
if game.isClient then print("thiết bị người chơi") end

Mỗi khung hình ​

lua
game.frame:connect(function(dt)   -- dt: số giây từ khung hình trước
    spinner.rotation += vec3(0, 90 * dt, 0)
end)

Trên server nó chạy mỗi bước (60 lần một giây); trên thiết bị người chơi, mỗi khung hình được vẽ.

Khi server tắt ​

lua
game.closing:connect(function()
    -- mọi người chơi vẫn còn đây: lưu những gì game giữ chung cho mọi người
end)

Server chờ các hàm xử lý closing (và các hàm players.left chạy sau đó) tối đa 20 giây. Xem Lưu dữ liệu.