الأحداث البعيدة واستدعاءات الوظائف

*This content is translated using AI (Beta) and may contain errors. To view this page in English, click here.

ألعاب Roblox متعددة اللاعبين بشكل افتراضي، لذلك تتواصل جميع الألعاب بطبيعتها بين الخادم واللاعبين المتصلين. في أبسط الحالات، مع تحرك اللاعبين لشخصياتهم، يتم التواصل ببعض خصائص Humanoid، مثل الحالات، إلى الخادم، الذي يمرر هذه المعلومات إلى لاعبين آخرين متصلين.

تتيح لك الأحداث البعيدة واستدعاءات الوظائف التواصل عبر حدود العميل والخادم:

  • RemoteEvents تمكّن الاتصال أحادي الاتجاه (إرسال طلب و عدم الانتظار للحصول على رد).
  • UnreliableRemoteEvents تمكّن الاتصال أحادي الاتجاه للبيانات التي تتغير باستمرار أو ليست حرجة لحالة اللعبة. تتاجر هذه الأحداث بالتسلسل والموثوقية لتحقيق أداء شبكة محسّن.
  • RemoteFunctions تمكّن التواصل ثنائي الاتجاه (إرسال طلب والانتظار حتى يتم تلقي رد من المستلم).

على عكس الأحداث القابلة للتوصيل، التي لديها فائدة أكثر محدودية، فإن حالات الاستخدام للأحداث البعيدة والوظائف كثيرة جدًا ليتم سردها:

  • أسلوب اللعب - يمكن أن تتطلب الألعاب الأساسية، مثل وصول لاعب إلى نهاية مستوى، حدثًا بعيدًا. يتم إخطار نص عميل الخادم، ثم تعيد نصوص الخادم ضبط موقع اللاعب.
  • التحقق من الخادم - إذا حاول لاعب شرب جرعة، فهل لديهم تلك الجرعة حقًا؟ لضمان fairness، يجب أن يكون الخادم هو مصدر الحقيقة للعبة. يمكن لبرنامج نصي عميل استخدام حدث بعيد لإخطار الخادم بأن اللاعب يشرب جرعة، ثم يمكن لنصوص الخادم أن تقرر ما إذا كان اللاعب يمتلك تلك الجرعة وما إذا كان يجب منح أي فوائد.
  • تحديثات واجهة المستخدم - مع تغير حالة اللعبة، يمكن لنصوص الخادم استخدام أحداث بعيدة لإخطار العملاء بالتغيرات في النقاط، والأهداف، وما إلى ذلك.
  • مشتريات السوق داخل اللعبة - لرؤية مثال على تطبيق يستخدم وظائف بعيدة، راجع مشتريات الاشتراك المنبثقة.

مرجع سريع

تعمل الجداول التالية كمرجع سريع لكيفية استخدام RemoteEvents وRemoteFunctions للتواصل بين العميل والخادم.

عميل → خادم
عميلRemoteEvent:FireServer(args)
خادمRemoteEvent.OnServerEvent:Connect(function(player, args))
خادم → عميل
خادمRemoteEvent:FireClient(player, args)
عميلRemoteEvent.OnClientEvent:Connect(function(args))
خادم → جميع العملاء
خادمRemoteEvent:FireAllClients(args)
عميلRemoteEvent.OnClientEvent:Connect(function(args))

الأحداث البعيدة

يسهل كائن RemoteEvent التواصل غير المتزامن، أحادي الاتجاه عبر حدود العميل والخادم دون الانتظار للحصول على رد.

لإنشاء RemoteEvent جديد عبر نافذة Explorer في Studio:

  1. مرر فوق الحاوية التي تريد إدراج RemoteEvent فيها. لضمان الوصول لكل من الخادم والعميل، يجب أن تكون موجودة في مكان يمكن لكلا الجانبين رؤيتها، مثل ReplicatedStorage، على الرغم من أنه في بعض الحالات يكون من المناسب تخزينها في Workspace أو داخل Tool.
  2. انقر على زر الذي يظهر إلى يمين اسم الحاوية وأدخل مثيل RemoteEvent.
  3. أعد تسمية المثيل لوصف غرضه.

بمجرد إنشاء RemoteEvent، يمكنه تسهيل التواصل أحادي الاتجاه من العميل إلى الخادم، من الخادم إلى العميل، أو من الخادم إلى جميع العملاء.

عميل → خادم
خادم → عميل
خادم → جميع العملاء

عميل → خادم

يمكنك استخدام LocalScript لتحفيز حدث على الخادم من خلال استدعاء طريقة FireServer() على RemoteEvent. إذا قمت بتمرير معلمات إلى FireServer()، فإنها تمرر إلى معالج الحدث على الخادم مع بعض القيود. لاحظ أن المعامل الأول لمتعامل الحدث على الخادم هو دائمًا كائن Player للعميل الذي يستدعيه، وتتبع المعلمات الإضافية.

عميلRemoteEvent:FireServer(args)
خادمRemoteEvent.OnServerEvent:Connect(function(player, args))

يقوم البرنامج النصي التالي بربط معالج حدث بـ OnServerEvent الذي ينشئ جزءًا جديدًا على الخادم. ثم يستدعي برنامج نصي العميل FireServer() على مثيل RemoteEvent مع Color وPosition المرغوب له.

ربط الحدث - نص

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Workspace = game:GetService("Workspace")
-- احصل على مرجع لمثيل الحدث البعيد
local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
local function onCreatePart(player, partColor, partPosition)
print(player.Name .. " fired the RemoteEvent")
local newPart = Instance.new("Part")
newPart.Color = partColor
newPart.Position = partPosition
newPart.Parent = Workspace
end
-- ربط الوظيفة بالحدث
remoteEvent.OnServerEvent:Connect(onCreatePart)
إطلاق الحدث - LocalScript

local ReplicatedStorage = game:GetService("ReplicatedStorage")
-- احصل على مرجع لمثيل الحدث البعيد
local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
-- أطلق الحدث البعيد ومرر معلمات إضافية
remoteEvent:FireServer(Color3.fromRGB(255, 0, 0), Vector3.new(0, 25, -20))

خادم → عميل

يمكنك استخدام Script لتحفيز حدث على عميل من خلال استدعاء طريقة FireClient() على RemoteEvent. المعامل الأول لطريقة FireClient() هو كائن Player للعميل الذي تريد الرد على الحدث له، والمعلمات الإضافية تضاف إلى العميل مع بعض القيود. لاحظ أن معالج الحدث لا يحتاج إلى تضمين كائن Player كمعامله الأول لأنك يمكنك تحديد اللاعب على العميل من خلال Players.LocalPlayer.

خادمRemoteEvent:FireClient(player, args)
عميلRemoteEvent.OnClientEvent:Connect(function(args))

البرنامج النصي التالي يرتبط معالج حدث بالحدث OnClientEvent. ثم يقوم البرنامج النصي المصاحب بالاستماع للاعبين القادمين إلى الخادم واستدعاء FireClient() لكل منهم مع بيانات عشوائية.

ربط الحدث - LocalScript

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Players = game:GetService("Players")
-- احصل على مرجع لمثيل الحدث البعيد
local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
local player = Players.LocalPlayer
local function onNotifyPlayer(maxPlayers, respawnTime)
print("[Client] تم استقبال الحدث من اللاعب", player.Name)
print(maxPlayers, respawnTime)
end
-- ربط الوظيفة بالحدث
remoteEvent.OnClientEvent:Connect(onNotifyPlayer)
إطلاق الحدث - نص

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Players = game:GetService("Players")
-- احصل على مرجع لمثيل الحدث البعيد
local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
-- استمع للاعبين القادمين وأطلق الحدث البعيد لكل منهم
local function onPlayerAdded(player)
print("[Server] إطلاق الحدث للاعب", player.Name)
remoteEvent:FireClient(player, Players.MaxPlayers, Players.RespawnTime)
end
Players.PlayerAdded:Connect(onPlayerAdded)

خادم → جميع العملاء

يمكنك استخدام Script لتحفيز حدث على جميع العملاء من خلال استدعاء طريقة FireAllClients() على RemoteEvent. على عكس FireClient()، لا تتطلب طريقة FireAllClients() وجود كائن Player لأنها تطلق RemoteEvent لجميع العملاء.

خادمRemoteEvent:FireAllClients(args)
عميلRemoteEvent.OnClientEvent:Connect(function(args))

البرنامج النصي التالي يرتبط معالج حدث بالحدث OnClientEvent والذي يخرج وقت العد التنازلي المتبقي. ثم يستدعي البرنامج النصي المصاحب FireAllClients() في حلقة كل ثانية لإطلاق RemoteEvent لجميع العملاء.

ربط الحدث - LocalScript

local ReplicatedStorage = game:GetService("ReplicatedStorage")
-- احصل على مرجع لمثيل الحدث البعيد
local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
local function onTimerUpdate(seconds)
print(seconds)
end
-- ربط الوظيفة بالحدث
remoteEvent.OnClientEvent:Connect(onTimerUpdate)
إطلاق الحدث - نص

local ReplicatedStorage = game:GetService("ReplicatedStorage")
-- احصل على مرجع لمثيل الحدث البعيد
local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
local countdown = 5
-- إطلاق RemoteEvent كل ثانية حتى ينتهي الوقت
for timeRemaining = -1, countdown do
remoteEvent:FireAllClients(countdown - timeRemaining)
task.wait(1)
end

استدعاءات بعيدة

يسهل كائن RemoteFunction التواصل المتزامن، ثنائي الاتجاه عبر حدود العميل والخادم. يقوم مرسل وظيفة بعيدة بالانتظار حتى يتلقى ردًا من المستلم.

لإنشاء RemoteFunction جديد عبر نافذة Explorer في Studio:

  1. مرر فوق الحاوية التي تريد إدراج RemoteFunction فيها. لضمان الوصول لكل من الخادم والعميل، يجب أن تكون موجودة في مكان يمكن لكلا الجانبين رؤيتها، مثل ReplicatedStorage، على الرغم من أنه في بعض الحالات، من المناسب تخزينها في Workspace أو داخل Tool.
  2. انقر على زر الذي يظهر إلى يمين اسم الحاوية وأدخل مثيل RemoteFunction.
  3. أعد تسمية المثيل لوصف غرضه.

بمجرد إنشاء RemoteFunction، يمكنه تسهيل التواصل ثنائي الاتجاه بين العميل والخادم أو بين الخادم والعميل.

عميل → خادم → عميل
خادم → عميل → خادم

عميل → خادم → عميل

يمكنك استخدام LocalScript لاستدعاء وظيفة على الخادم من خلال استدعاء طريقة InvokeServer() على RemoteFunction. على عكس حدث بعيد، يتسبب LocalScript الذي يستدعي RemoteFunction في انتظار حتى يعود الاستدعاء. تمرر المعلمات التي تقدمها إلى InvokeServer() إلى استدعاء OnServerInvoke لكائن RemoteFunction مع بعض القيود. لاحظ أنه إذا قمت بتعريف عدة استدعاءات لنفس RemoteFunction، فإن فقط التعريف الأخير ينفذ.

عميلRemoteFunction:InvokeServer(args)
خادمRemoteFunction.OnServerInvoke = function(player, args)

البرنامج النصي التالي يعرف وظيفة الاستدعاء عبر OnServerInvoke ويعيد Part المطلوب من خلال قيمة return الخاصة به. ثم يقوم برنامج النص المحلي بالاتصال بـ InvokeServer() مع معلمات إضافية تحدد لون الجزء المطلوب وموقعه.

ربط الاستدعاء - نص

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Workspace = game:GetService("Workspace")
-- احصل على مرجع لمثيل الوظيفة البعيدة
local remoteFunction = ReplicatedStorage:FindFirstChildOfClass("RemoteFunction")
-- وظيفة الاستدعاء
local function createPart(player, partColor, partPosition)
print(player.Name .. " requested a new part")
local newPart = Instance.new("Part")
newPart.Color = partColor
newPart.Position = partPosition
newPart.Parent = Workspace
return newPart
end
-- تعيين الوظيفة كاستدعاء للوظيفة البعيدة
remoteFunction.OnServerInvoke = createPart
استدعاء الحدث - LocalScript

local ReplicatedStorage = game:GetService("ReplicatedStorage")
-- احصل على مرجع لمثيل الوظيفة البعيدة
local remoteFunction = ReplicatedStorage:FindFirstChildOfClass("RemoteFunction")
-- مرر لونًا وموقعًا عند استدعاء الاستدعاء
local newPart = remoteFunction:InvokeServer(Color3.fromRGB(255, 0, 0), Vector3.new(0, 25, -20))
-- عرض مرجع الجزء المعاد
print("أنشأ الخادم الجزء المطلوب:", newPart)

خادم → عميل → خادم

يمكنك استخدام Script لاستدعاء وظيفة على العميل من خلال استدعاء طريقة InvokeClient() على RemoteFunction، ولكن توجد مخاطر خطيرة كما يلي:

  • إذا حدث خطأ على العميل، فإن الخادم يصب ذلك الخطأ أيضًا.
  • إذا تم قطع الاتصال بالعميل أثناء استدعائه، فإن InvokeClient() يظهر خطأ.
  • إذا لم يعيد العميل قيمة، فإن الخادم ينتظر للأبد.

لإجراءات لا تتطلب اتصالات ثنائية الاتجاه، مثل تحديث واجهة المستخدم، استخدم RemoteEvent وتواصل من الخادم إلى العميل.

قيود المعاملات

عند إطلاق RemoteEvent أو استدعاء RemoteFunction، فإنه يقوم بإعادة توجيه أي معاملات تمررها مع الحدث أو إلى دالة الاستدعاء. يمكن تمرير أي نوع من كائنات Roblox مثل Enum، أو Instance، أو غيرها، بالإضافة إلى أنواع Luau مثل الأرقام، والسلاسل، والقيم المنطقية، على الرغم من أنه يجب عليك استكشاف القيود التالية بحذر.

الفهارس غير النصية

إذا كانت أي فهارس لجدول يتم تمريره من أنواع غير نصية مثل Instance، أو بيانات مستخدم، أو دالة، فإن Roblox تقوم تلقائيًا بتحويل تلك الفهارس إلى نصوص.

ربط الحدث - LocalScript

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
-- ربط الوظيفة بالحدث
remoteEvent.OnClientEvent:Connect(onEventFire)
إطلاق الحدث - نص

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Players = game:GetService("Players")
local Workspace = game:GetService("Workspace")
local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
-- استمع للاعبين القادمين وأطلق الحدث البعيد لكل منهم
local function onPlayerAdded(player)
remoteEvent:FireClient(player,
{
[Workspace.Baseplate] = true
}
)
end
Players.PlayerAdded:Connect(onPlayerAdded)

الوظائف المرسلة

لن يتم تكرار الدوال المضمنة كمعاملات لـ RemoteEvent أو RemoteFunction عبر حدود العميل والخادم، مما يجعل من المستحيل تمرير الدوال عن بُعد. بدلاً من ذلك، ستكون قيمة المعامل في الجانب المستلم nil.

ربط الحدث - LocalScript

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
-- إطلاق الحدث البعيد مع دالة كمعامل
remoteEvent:FireAllClients(testFunction)

فهرسة الجدول

إذا قمت بتمرير جدول من البيانات، فلا تمرر جدولًا مختلطًا من مفاتيح رقمية ونصية. بدلاً من ذلك، مرر جدول يتكون كليًا من أزواج مفتاح-قيمة (قاموس) أو كليًا من فهارس رقمية.

ربط الحدث - نص

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
-- ربط الوظيفة بالحدث
remoteEvent.OnServerEvent:Connect(onEventFire)
إطلاق الحدث - LocalScript

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
-- جدول ذو فهارس رقمية
local inventoryData = {
"Sword", "Bow"
}
-- جدول قاموس
local characterData = {
CharName = "Diva Dragonslayer",
CharClass = "Rogue"
}
remoteEvent:FireServer(inventoryData)
remoteEvent:FireServer(characterData)

هويات الجدول

تُنسخ الجداول التي تمرر كمعاملات في الأحداث البعيدة/الاستدعاءات، مما يعني أنها لن تكون بالضبط مكافئة لتلك التي تم تقديمها عند إطلاق الحدث أو استدعاء الاستدعاء. ولن تكون الجداول المعادة إلى المستدعي مكافئة تمامًا لتلك المقدمة. يمكنك إثبات ذلك من خلال تشغيل البرنامج النصي التالي على RemoteFunction ومشاهدة كيف تختلف هويات الجدول.

ربط الاستدعاء - نص

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local remoteFunction = ReplicatedStorage:FindFirstChildOfClass("RemoteFunction")
-- وظيفة الاستدعاء
local function returnTable(player, passedTable)
-- إخراج هوية الجدول عند الاستدعاء
print(tostring(passedTable)) --> table: 0x48eb7aead27563d9
return passedTable
end
-- تعيين الوظيفة كاستدعاء للوظيفة البعيدة
remoteFunction.OnServerInvoke = returnTable
استدعاء الحدث - LocalScript

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local remoteFunction = ReplicatedStorage:FindFirstChildOfClass("RemoteFunction")
local inventoryData = {
"Sword", "Bow"
}
-- إخراج هوية الجدول الأصلية
print(tostring(inventoryData)) --> table: 0x059bcdbb2b576549
local invokeReturn = remoteFunction:InvokeServer(inventoryData)
-- إخراج هوية الجدول عند العودة
print(tostring(invokeReturn)) --> table: 0x9fcae7919563a0e9

الجداول الفوقية

إذا كان للجدول جدول فوقي، فإن جميع معلومات الجدول الفوقي تضيع أثناء النقل. في عينة الكود التالية، خاصية NumWheels هي جزء من جدول Car فوقي. عندما يتلقى الخادم الجدول التالي، يحتوي جدول truck على خاصية Name ولكن ليس خاصية NumWheels.

ربط الحدث - نص

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
local function onEvent(player, param)
print(param) --> {["Name"] = "MyTruck"}
end
-- ربط الوظيفة بالحدث
remoteEvent.OnServerEvent:Connect(onEvent)
إطلاق الحدث - LocalScript

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)
-- إطلاق الحدث بجدول يتضمن جدولًا فوقيًا
remoteEvent:FireServer(truck)

الكائنات غير المعاد تكرارها

إذا قام RemoteEvent أو RemoteFunction بتمرير قيمة ليست مرئية للمستلم، فإن Roblox لا تكررها عبر حدود العميل والخادم وتعيد nil بدلاً من القيمة. على سبيل المثال، إذا قام Script بتمرير نسل من ServerStorage، فسيتلقى العميل الذي يستمع إلى الحدث قيمة nil لأن هذا الكائن غير قابل للتكرار بالنسبة للعميل.

إطلاق الحدث - نص

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local ServerStorage = game:GetService("ServerStorage")
local Players = game:GetService("Players")
local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
-- سيتم استقباله كـ "nil" لأن العميل لا يمكنه الوصول إلى ServerStorage
local storedPart = Instance.new("Part")
storedPart.Parent = ServerStorage
local function onPlayerAdded(player)
remoteEvent:FireClient(player, storedPart)
end
Players.PlayerAdded:Connect(onPlayerAdded)

بالمثل، إذا قمت بإنشاء جزء في LocalScript وحاولت تمريره إلى Script، فسيرى الخادم nil لأن الجزء غير قابل للتكرار بالنسبة للخادم.

إطلاق الحدث - LocalScript

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Workspace = game:GetService("Workspace")
local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
-- سيتم استقباله كـ "nil" لأن الخادم لا يعرف عن هذا الجزء
local clientPart = Instance.new("Part")
clientPart.Parent = Workspace
remoteEvent:FireServer(clientPart)
©2026 شركة Roblox Corporation. تُعد منصّة Roblox، وشعار Roblox وشعار "توسيع حدود المخيلة"، من ضمن علاماتنا التجارية المسجّلة وغير المسجّلة في الولايات المتحدة وبلدان أخرى.