Các trò chơi Roblox là đa người chơi theo mặc định, vì vậy tất cả các trò chơi đều giao tiếp giữa server và các client được kết nối của người chơi. Trong trường hợp đơn giản nhất, khi người chơi di chuyển nhân vật của họ, một số thuộc tính Humanoid, chẳng hạn như trạng thái, được truyền đến server, server sẽ chuyển thông tin này đến các client khác được kết nối.
Các sự kiện từ xa và callback cho phép bạn giao tiếp qua ranh giới client-server:
- RemoteEvents cho phép giao tiếp một chiều (gửi yêu cầu và không chờ phản hồi).
- UnreliableRemoteEvents cho phép giao tiếp một chiều cho dữ liệu thay đổi liên tục hoặc không quan trọng đối với trạng thái của trò chơi. Các sự kiện này đánh đổi thứ tự và độ tin cậy để cải thiện hiệu suất mạng.
- RemoteFunctions cho phép giao tiếp hai chiều (gửi yêu cầu và chờ cho đến khi nhận được phản hồi từ người nhận).
Khác với các sự kiện có thể liên kết, có tính hữu dụng hạn chế hơn, các trường hợp sử dụng cho các sự kiện và hàm từ xa thì quá nhiều để liệt kê:
- Gameplay - Gameplay cơ bản, chẳng hạn như một người chơi đạt đến cuối một cấp độ, có thể yêu cầu một sự kiện từ xa. Một script client thông báo cho server, và các script server đặt lại vị trí của người chơi.
- Xác minh server - Nếu một người chơi cố gắng uống một loại thuốc, họ có thực sự có loại thuốc đó không? Để đảm bảo công bằng, server phải là nguồn sự thật cho một trò chơi. Một script client có thể sử dụng một sự kiện từ xa để thông báo cho server rằng người chơi đang uống một loại thuốc, và sau đó các script server có thể quyết định xem người chơi thực sự có loại thuốc đó hay không và có nên trao bất kỳ lợi ích nào không.
- Cập nhật giao diện người dùng - Khi trạng thái của trò chơi thay đổi, các script server có thể sử dụng các sự kiện từ xa để thông báo cho các client về những thay đổi trong điểm số, mục tiêu, v.v.
- Mua hàng trong Marketplace trong trò chơi - Để xem một ví dụ về việc triển khai sử dụng các hàm từ xa, hãy xem Mua hàng đăng ký nhắc nhở.
Tham khảo nhanh
Các bảng sau đây phục vụ như một tham khảo nhanh về cách sử dụng RemoteEvents và RemoteFunctions để giao tiếp giữa client và server.
| Client → Server | |
|---|---|
| Client | RemoteEvent:FireServer(args) |
| Server | RemoteEvent.OnServerEvent:Connect(function(player, args)) |
| Server → Client | |
| Server | RemoteEvent:FireClient(player, args) |
| Client | RemoteEvent.OnClientEvent:Connect(function(args)) |
| Server → Tất cả Clients | |
| Server | RemoteEvent:FireAllClients(args) |
| Client | RemoteEvent.OnClientEvent:Connect(function(args)) |
Sự kiện từ xa
Một đối tượng RemoteEvent tạo điều kiện cho giao tiếp không đồng bộ, một chiều qua ranh giới client-server mà không chờ phản hồi.
Để tạo một RemoteEvent mới qua cửa sổ Explorer trong Studio:
- Di chuột qua container mà bạn muốn chèn RemoteEvent. Để đảm bảo cả server và client đều có thể truy cập, nó phải ở một nơi mà cả hai bên đều có thể nhìn thấy, chẳng hạn như ReplicatedStorage, mặc dù trong một số trường hợp, việc lưu trữ nó trong Workspace hoặc bên trong một Tool là phù hợp.
- Nhấp vào nút ⊕ xuất hiện bên phải tên của container và chèn một instance RemoteEvent.
- Đổi tên instance để mô tả mục đích của nó.
Khi bạn đã tạo một RemoteEvent, nó có thể tạo điều kiện cho giao tiếp một chiều từ client đến server, từ server đến client, hoặc từ server đến tất cả clients.



Client → server
Bạn có thể sử dụng một LocalScript để kích hoạt một sự kiện trên server bằng cách gọi phương thức FireServer() trên một RemoteEvent. Nếu bạn truyền các đối số cho FireServer(), chúng sẽ được truyền đến trình xử lý sự kiện trên server với một số giới hạn. Lưu ý rằng tham số đầu tiên của trình xử lý sự kiện trên server luôn là đối tượng Player của client gọi nó, và các tham số bổ sung theo sau.
| Client | RemoteEvent:FireServer(args) |
| Server | RemoteEvent.OnServerEvent:Connect(function(player, args)) |
Đoạn Script sau đây kết nối một trình xử lý sự kiện với OnServerEvent tạo ra một Part mới trên server. Đoạn LocalScript đi kèm sau đó gọi FireServer() trên instance RemoteEvent với Color và Position mong muốn cho phần.
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Workspace = game:GetService("Workspace")
-- Lấy tham chiếu đến instance sự kiện từ xa
local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
local function onCreatePart(player, partColor, partPosition)
print(player.Name .. " đã kích hoạt RemoteEvent")
local newPart = Instance.new("Part")
newPart.Color = partColor
newPart.Position = partPosition
newPart.Parent = Workspace
end
-- Kết nối hàm với sự kiện
remoteEvent.OnServerEvent:Connect(onCreatePart)local ReplicatedStorage = game:GetService("ReplicatedStorage")
-- Lấy tham chiếu đến instance sự kiện từ xa
local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
-- Kích hoạt sự kiện từ xa và truyền các đối số bổ sung
remoteEvent:FireServer(Color3.fromRGB(255, 0, 0), Vector3.new(0, 25, -20))Server → client
Bạn có thể sử dụng một Script để kích hoạt một sự kiện trên một client bằng cách gọi phương thức FireClient() trên một RemoteEvent. Đối số đầu tiên cho FireClient() là đối tượng Player của client mà bạn muốn phản hồi sự kiện, và các đối số bổ sung sẽ được truyền đến client với một số giới hạn. Lưu ý rằng trình xử lý sự kiện không cần bao gồm đối tượng Player như là đối số đầu tiên của nó vì bạn có thể xác định người chơi trên client với Players.LocalPlayer.
| Server | RemoteEvent:FireClient(player, args) |
| Client | RemoteEvent.OnClientEvent:Connect(function(args)) |
Đoạn LocalScript sau đây kết nối một trình xử lý sự kiện với sự kiện OnClientEvent. Đoạn Script đi kèm sau đó lắng nghe các người chơi đến server và gọi FireClient() cho mỗi người với dữ liệu tùy ý.
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Players = game:GetService("Players")
-- Lấy tham chiếu đến instance sự kiện từ xa
local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
local player = Players.LocalPlayer
local function onNotifyPlayer(maxPlayers, respawnTime)
print("[Client] Sự kiện đã nhận bởi người chơi", player.Name)
print(maxPlayers, respawnTime)
end
-- Kết nối hàm với sự kiện
remoteEvent.OnClientEvent:Connect(onNotifyPlayer)local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Players = game:GetService("Players")
-- Lấy tham chiếu đến instance sự kiện từ xa
local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
-- Lắng nghe các người chơi đến và phát sự kiện từ xa cho mỗi người
local function onPlayerAdded(player)
print("[Server] Kích hoạt sự kiện cho người chơi", player.Name)
remoteEvent:FireClient(player, Players.MaxPlayers, Players.RespawnTime)
end
Players.PlayerAdded:Connect(onPlayerAdded)Server → tất cả clients
Bạn có thể sử dụng một Script để kích hoạt một sự kiện trên tất cả các client bằng cách gọi phương thức FireAllClients() trên một RemoteEvent. Khác với FireClient(), phương thức FireAllClients() không yêu cầu một đối tượng Player vì nó phát RemoteEvent đến tất cả các client.
| Server | RemoteEvent:FireAllClients(args) |
| Client | RemoteEvent.OnClientEvent:Connect(function(args)) |
Đoạn LocalScript sau đây kết nối một trình xử lý sự kiện với sự kiện OnClientEvent mà xuất ra thời gian đếm ngược còn lại. Đoạn Script đi kèm sau đó gọi FireAllClients() trong một vòng lặp mỗi giây để phát RemoteEvent cho tất cả các client.
local ReplicatedStorage = game:GetService("ReplicatedStorage")
-- Lấy tham chiếu đến instance sự kiện từ xa
local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
local function onTimerUpdate(seconds)
print(seconds)
end
-- Kết nối hàm với sự kiện
remoteEvent.OnClientEvent:Connect(onTimerUpdate)local ReplicatedStorage = game:GetService("ReplicatedStorage")
-- Lấy tham chiếu đến instance sự kiện từ xa
local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
local countdown = 5
-- Kích hoạt RemoteEvent mỗi giây cho đến khi thời gian hết
for timeRemaining = -1, countdown do
remoteEvent:FireAllClients(countdown - timeRemaining)
task.wait(1)
endCallback từ xa
Một đối tượng RemoteFunction tạo điều kiện cho giao tiếp đồng bộ, hai chiều qua ranh giới client-server. Người gửi một hàm từ xa sẽ chờ cho đến khi nhận được phản hồi từ người nhận.
Để tạo một RemoteFunction mới qua cửa sổ Explorer trong Studio:
- Di chuột qua container mà bạn muốn chèn RemoteFunction. Để đảm bảo cả server và client đều có thể truy cập, nó phải ở một nơi mà cả hai bên đều có thể nhìn thấy, chẳng hạn như ReplicatedStorage, mặc dù trong một số trường hợp, việc lưu trữ nó trong Workspace hoặc bên trong một Tool là phù hợp.
- Nhấp vào nút ⊕ xuất hiện bên phải tên của container và chèn một instance RemoteFunction.
- Đổi tên instance để mô tả mục đích của nó.
Khi bạn đã tạo một RemoteFunction, nó có thể tạo điều kiện cho giao tiếp hai chiều giữa client và server hoặc giữa server và client.


Client → server → client
Bạn có thể sử dụng một LocalScript để gọi một hàm trên server bằng cách gọi phương thức InvokeServer() trên một RemoteFunction. Khác với một sự kiện từ xa, LocalScript gọi RemoteFunction sẽ chờ cho đến khi callback trả về. Các đối số mà bạn truyền cho InvokeServer() sẽ được truyền đến callback OnServerInvoke của RemoteFunction với một số giới hạn. Lưu ý rằng nếu bạn định nghĩa nhiều callback cho cùng một RemoteFunction, chỉ định nghĩa cuối cùng sẽ được thực thi.
| Client | RemoteFunction:InvokeServer(args) |
| Server | RemoteFunction.OnServerInvoke = function(player, args) |
Đoạn Script sau đây định nghĩa hàm callback qua OnServerInvoke và trả về Part được yêu cầu thông qua giá trị return của nó. Đoạn LocalScript đi kèm sau đó gọi InvokeServer() với các đối số bổ sung xác định màu sắc và vị trí của phần được yêu cầu.
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Workspace = game:GetService("Workspace")
-- Lấy tham chiếu đến instance hàm từ xa
local remoteFunction = ReplicatedStorage:FindFirstChildOfClass("RemoteFunction")
-- Hàm callback
local function createPart(player, partColor, partPosition)
print(player.Name .. " đã yêu cầu một phần mới")
local newPart = Instance.new("Part")
newPart.Color = partColor
newPart.Position = partPosition
newPart.Parent = Workspace
return newPart
end
-- Đặt hàm làm callback của hàm từ xa
remoteFunction.OnServerInvoke = createPartlocal ReplicatedStorage = game:GetService("ReplicatedStorage")
-- Lấy tham chiếu đến instance hàm từ xa
local remoteFunction = ReplicatedStorage:FindFirstChildOfClass("RemoteFunction")
-- Truyền một màu sắc và vị trí khi gọi callback
local newPart = remoteFunction:InvokeServer(Color3.fromRGB(255, 0, 0), Vector3.new(0, 25, -20))
-- Xuất ra tham chiếu đến phần đã trả về
print("Server đã tạo phần được yêu cầu:", newPart)Server → client → server
Bạn có thể sử dụng một Script để gọi một hàm trên client bằng cách gọi phương thức InvokeClient() trên một RemoteFunction, nhưng điều này có những rủi ro nghiêm trọng như sau:
- Nếu client gặp lỗi, server cũng sẽ gặp lỗi.
- Nếu client ngắt kết nối trong khi đang được gọi, InvokeClient() sẽ gặp lỗi.
- Nếu client không trả về giá trị, server sẽ chờ mãi mãi.
Đối với các hành động không yêu cầu giao tiếp hai chiều, chẳng hạn như cập nhật GUI, hãy sử dụng RemoteEvent và giao tiếp từ server đến client.
Đảm bảo giao hàng
Mỗi loại từ xa đưa ra những lời hứa khác nhau về việc liệu một tin nhắn có đến nơi và theo thứ tự nào. Những lời hứa này chỉ áp dụng cho một kết nối duy nhất trong một hướng duy nhất, có nghĩa là từ server đến một client cụ thể, hoặc từ một client cụ thể đến server.
RemoteEvents
RemoteEvents là đáng tin cậy và có thứ tự:
- Nếu một tin nhắn bị mất trong quá trình truyền, Roblox sẽ truyền lại cho đến khi nó đến nơi, miễn là người nhận vẫn kết nối.
- Các tin nhắn đến theo thứ tự bạn phát chúng, bao gồm cả qua các instance RemoteEvent khác nhau. Ví dụ, nếu server phát sự kiện A, sau đó B, sau đó A một lần nữa đến cùng một client, client đó sẽ nhận A, B, A. Điều này áp dụng cho dù bạn sử dụng FireClient() hay FireAllClients().
- Nếu một client phát các sự kiện nhanh hơn giới hạn throttling, server sẽ xử lý các sự kiện thừa sau đó thay vì bỏ qua chúng, và chúng giữ nguyên thứ tự của chúng.
Một tin nhắn đáng tin cậy, có thứ tự vẫn có thể không đến được mã của bạn trong các trường hợp sau:
- Không có trình xử lý nào được kết nối. Nếu không có gì được kết nối với OnServerEvent hoặc OnClientEvent khi một tin nhắn đến, Roblox sẽ xếp hàng nó và giao nó, theo thứ tự, ngay khi một trình xử lý kết nối. Hàng đợi này bị giới hạn cả về số lượng và bộ nhớ. Khi nó đầy, Roblox sẽ loại bỏ các tin nhắn tiếp theo và ghi lại lỗi Remote event invocation vào cửa sổ Output.
- Người nhận ngắt kết nối. Các tin nhắn chưa được giao khi một client rời đi sẽ bị mất.
Thứ tự áp dụng cho khi mỗi trình xử lý bắt đầu, không phải khi nó hoàn thành. Nếu một trình xử lý chờ, chẳng hạn như bằng cách gọi task.wait() hoặc WaitForChild(), Roblox có thể bắt đầu xử lý tin nhắn tiếp theo trước khi trình xử lý trước đó tiếp tục.
RemoteFunctions
RemoteFunctions gửi các yêu cầu và phản hồi một cách đáng tin cậy, vì vậy Roblox sẽ truyền lại các tin nhắn bị mất miễn là cả hai bên vẫn kết nối. Bởi vì InvokeServer() và InvokeClient() chờ cho đến khi một phản hồi đến, một luồng đơn không thể có nhiều hơn một yêu cầu đang bay. Các luồng riêng biệt có thể gọi cùng một lúc, mặc dù, và nếu một callback chờ, các phản hồi có thể đến theo thứ tự khác với các yêu cầu đã được gửi.
Nếu không có callback nào được gán cho OnServerInvoke hoặc OnClientInvoke, Roblox sẽ xếp hàng các yêu cầu cho đến khi có một cái. Hàng đợi này có cùng loại giới hạn như hàng đợi RemoteEvent.
UnreliableRemoteEvents
UnreliableRemoteEvents không đảm bảo việc giao hàng hay thứ tự. Chúng cũng không có mối quan hệ thứ tự với RemoteEvents hoặc RemoteFunctions. Roblox có thể bỏ qua một tin nhắn trong bất kỳ trường hợp nào sau đây, mà không gửi lại:
- Tin nhắn bị mất trong quá trình truyền.
- Mạng bị tắc nghẽn và tin nhắn chờ quá lâu để gửi.
- Tải trọng lớn hơn 1.000 byte.
- Client phát nhanh hơn giới hạn throttling. Khác với RemoteEvent, server sẽ bỏ qua các tin nhắn thừa thay vì trì hoãn chúng.
- Không có gì được kết nối với OnServerEvent hoặc OnClientEvent khi tin nhắn đến. Khác với RemoteEvent, Roblox sẽ loại bỏ tin nhắn ngay lập tức thay vì xếp hàng nó.
Roblox cũng không chờ một tin nhắn trước đó đến nơi trước khi xử lý một tin nhắn sau đó, vì vậy các tin nhắn có thể đến không theo thứ tự. Nếu thứ tự quan trọng, hãy bao gồm một dấu thời gian hoặc số thứ tự trong mỗi tin nhắn và bỏ qua các tin nhắn cũ hơn so với tin nhắn mới nhất mà bạn đã xử lý.
Giới hạn throttling và kích thước
Các tin nhắn từ client đến server phải tuân theo giới hạn tỷ lệ mà mỗi loại từ xa chia sẻ giữa tất cả các instance của nó. Để biết các giới hạn hiện tại, hãy xem phần Throttling của RemoteEvent và các giới hạn tải trọng trong UnreliableRemoteEvent.
Giới hạn đối số
Khi bạn phát một RemoteEvent hoặc gọi một RemoteFunction, nó sẽ chuyển tiếp bất kỳ đối số nào mà bạn truyền cùng với sự kiện hoặc đến hàm callback. Bất kỳ loại đối tượng Roblox nào như Enum, Instance, hoặc các loại khác có thể được truyền, cũng như các loại Luau như số, chuỗi và boolean, mặc dù bạn nên cẩn thận khám phá các giới hạn sau.
Chỉ số không phải chuỗi
Nếu bất kỳ chỉ số nào của một bảng được truyền là các loại không phải chuỗi như Instance, userdata, hoặc hàm, Roblox sẽ tự động chuyển đổi các chỉ số đó thành chuỗi.
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
local function onEventFire(passedTable)
for k, v in passedTable do
print(typeof(k)) --> string
end
end
-- Kết nối hàm với sự kiện
remoteEvent.OnClientEvent:Connect(onEventFire)local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Players = game:GetService("Players")
local Workspace = game:GetService("Workspace")
local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
-- Lắng nghe các người chơi đến và phát sự kiện từ xa cho mỗi người
local function onPlayerAdded(player)
remoteEvent:FireClient(player,
{
[Workspace.Baseplate] = true
}
)
end
Players.PlayerAdded:Connect(onPlayerAdded)Các hàm được truyền
Các hàm được bao gồm như các đối số cho một RemoteEvent hoặc RemoteFunction sẽ không được sao chép qua ranh giới client-server, khiến cho việc truyền các hàm từ xa trở nên không thể. Thay vào đó, đối số kết quả ở phía nhận sẽ là nil.
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
local function onClientEvent(func)
print(func) --> nil
end
remoteEvent.OnClientEvent:Connect(onClientEvent)local ReplicatedStorage = game:GetService("ReplicatedStorage")
local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
local function testFunction()
print("Hello world!")
end
-- Kích hoạt sự kiện từ xa với hàm như một đối số
remoteEvent:FireAllClients(testFunction)Chỉ mục bảng
Nếu bạn truyền một bảng dữ liệu, đừng truyền một bảng hỗn hợp các khóa số và chuỗi. Thay vào đó, hãy truyền một bảng bao gồm hoàn toàn các cặp khóa-giá trị (từ điển) hoặc hoàn toàn các chỉ số số.
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
local function onEventFire(player, passedTable)
for k, v in passedTable do
print(k .. " = " .. v)
--> 1 = Sword
--> 2 = Bow
--> CharName = Diva Dragonslayer
--> CharClass = Rogue
end
end
-- Kết nối hàm với sự kiện
remoteEvent.OnServerEvent:Connect(onEventFire)local ReplicatedStorage = game:GetService("ReplicatedStorage")
local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
-- Bảng chỉ số số
local inventoryData = {
"Sword", "Bow"
}
-- Bảng từ điển
local characterData = {
CharName = "Diva Dragonslayer",
CharClass = "Rogue"
}
remoteEvent:FireServer(inventoryData)
remoteEvent:FireServer(characterData)Danh tính bảng
Các bảng được truyền làm đối số cho các sự kiện/callback từ xa sẽ được sao chép, có nghĩa là chúng sẽ không hoàn toàn tương đương với những bảng được cung cấp khi phát sự kiện hoặc gọi callback. Các bảng được trả về cho người gọi cũng sẽ không hoàn toàn tương đương với những bảng được cung cấp. Bạn có thể chứng minh điều này bằng cách chạy đoạn mã sau trên một RemoteFunction và quan sát cách mà danh tính bảng khác nhau.
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local remoteFunction = ReplicatedStorage:FindFirstChildOfClass("RemoteFunction")
-- Hàm callback
local function returnTable(player, passedTable)
-- Xuất ra danh tính bảng khi được gọi
print(tostring(passedTable)) --> table: 0x48eb7aead27563d9
return passedTable
end
-- Đặt hàm làm callback của hàm từ xa
remoteFunction.OnServerInvoke = returnTablelocal ReplicatedStorage = game:GetService("ReplicatedStorage")
local remoteFunction = ReplicatedStorage:FindFirstChildOfClass("RemoteFunction")
local inventoryData = {
"Sword", "Bow"
}
-- Xuất ra danh tính bảng gốc
print(tostring(inventoryData)) --> table: 0x059bcdbb2b576549
local invokeReturn = remoteFunction:InvokeServer(inventoryData)
-- Xuất ra danh tính bảng khi trả về
print(tostring(invokeReturn)) --> table: 0x9fcae7919563a0e9Metatables
Nếu một bảng có một metatable, tất cả thông tin metatable sẽ bị mất trong quá trình truyền. Trong đoạn mã mẫu sau, thuộc tính NumWheels là một phần của metatable Car. Khi server nhận bảng sau, bảng truck có thuộc tính Name nhưng không có thuộc tính NumWheels.
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
local function onEvent(player, param)
print(param) --> {["Name"] = "MyTruck"}
end
-- Kết nối hàm với sự kiện
remoteEvent.OnServerEvent:Connect(onEvent)local ReplicatedStorage = game:GetService("ReplicatedStorage")
local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
local Car = {}
Car.NumWheels = 4
Car.__index = Car
local truck = {}
truck.Name = "MyTruck"
setmetatable(truck, Car)
-- Kích hoạt sự kiện với bảng bao gồm một metatable
remoteEvent:FireServer(truck)Các instance không được sao chép
Nếu một RemoteEvent hoặc RemoteFunction truyền một giá trị chỉ có thể nhìn thấy bởi người gửi, Roblox sẽ không sao chép nó qua ranh giới client-server và sẽ truyền nil thay vì giá trị đó. Ví dụ, nếu một Script truyền một phần tử con của ServerStorage, client lắng nghe sự kiện sẽ nhận được giá trị nil vì đối tượng đó không thể sao chép cho client.
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local ServerStorage = game:GetService("ServerStorage")
local Players = game:GetService("Players")
local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
-- Sẽ được nhận là "nil" vì client không thể truy cập ServerStorage
local storedPart = Instance.new("Part")
storedPart.Parent = ServerStorage
local function onPlayerAdded(player)
remoteEvent:FireClient(player, storedPart)
end
Players.PlayerAdded:Connect(onPlayerAdded)Tương tự, nếu bạn tạo một phần trong một LocalScript và cố gắng truyền nó đến một Script, server sẽ thấy nil vì phần đó không thể sao chép cho server.
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Workspace = game:GetService("Workspace")
local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
-- Sẽ được nhận là "nil" vì server không biết về phần này
local clientPart = Instance.new("Part")
clientPart.Parent = Workspace
remoteEvent:FireServer(clientPart)