ใน โมเดลอำนาจของเซิร์ฟเวอร์ เซิร์ฟเวอร์เป็น แหล่งที่มาของความจริง เพียงแหล่งเดียวสำหรับสถานะของเกมทั้งหมด และไคลเอนต์จะได้รับการไว้วางใจเพียงแค่รายงานการป้อนข้อมูลของตนเองเท่านั้น สถาปัตยกรรมนี้เป็นพื้นฐานของเน็ตโค้ดที่เล็งไปที่เกมแข่งขันที่ยุติธรรม เนื่องจากมันป้องกันไม่ให้เกิดการโกงรูปแบบต่างๆ เช่น flyhacks หรือ speedhacks โดยไม่ไว้วางใจให้ไคลเอนต์รายงานตำแหน่งหรือลักษณะของตนเอง
ข้อดี
ในระบบที่มีเจ้าของเซิร์ฟเวอร์อย่างหยาบๆ ไคลเอนต์จะส่งการป้อนข้อมูลไปยังเซิร์ฟเวอร์และแสดงผลลัพธ์ของเกมที่ส่งกลับโดยเซิร์ฟเวอร์ ในขณะที่ถูกต้องในทางเทคนิค แต่ระบบเช่นนี้จะเผชิญกับ การหน่วงเวลาในการป้อนข้อมูล อย่างมากเนื่องจากการกระทำของผู้เล่นทุกคนจะต้องเดินทางไปยังเซิร์ฟเวอร์ ถูกประมวลผล และส่งกลับไปยังไคลเอนต์ก่อนที่จะสามารถแสดงผลได้ สำหรับเกมส่วนใหญ่ โดยเฉพาะเกมที่มีความเร็วสูง การหน่วงเวลาในการเดินทางนี้อาจทำให้การเล่นรู้สึกช้า ไม่ตอบสนอง และไม่สามารถเล่นได้
ใน โมเดลอำนาจของเซิร์ฟเวอร์ ของ Roblox การหน่วงเวลาจะถูกชดเชยโดยการทำให้ไคลเอนต์คาดการณ์ผลของการป้อนข้อมูลของพวกเขาในทันที predict พร้อมกับส่งไปยังเซิร์ฟเวอร์ ตัวอย่างเช่น เมื่อผู้เล่นกดปุ่ม ไคลเอนต์จะไม่รอให้เซิร์ฟเวอร์ตอบกลับ แต่จะ คาดการณ์ ไปข้างหน้าหลายเฟรมจากสถานะของเซิร์ฟเวอร์ที่ทราบล่าสุด สิ่งนี้ช่วยให้ไคลเอนต์แสดงผลของการกระทำการป้อนข้อมูลได้ทันที ช่วยซ่อนการหน่วงเวลาของเครือข่ายและทำให้เกมรู้สึกตอบสนอง
บางครั้งไคลเอนต์อาจคาดการณ์ผิด (misprediction) และเนื่องจากการหน่วงเวลาในเครือข่าย ไคลเอนต์จะไม่รู้ว่ามันทำผิดพลาดจนกว่าจะผ่านไปหลายเฟรม ตัวอย่างเช่น:
เมื่อตรวจพบการคาดการณ์ผิด ไคลเอนต์จะต้องแก้ไขการคาดการณ์ตาม สถานะที่มีอำนาจ ของเซิร์ฟเวอร์ หากสถานะที่มีอำนาจแตกต่างจากสถานะที่ไคลเอนต์คาดการณ์ไว้ ไคลเอนต์จะต้อง rollback and resimulate เฟรมที่คาดการณ์ของตน ระบบของการคาดการณ์โดยไคลเอนต์ การรีเซ็ต และการจำลองใหม่นี้เรียกว่า "การชดเชยการหน่วงเวลา" และช่วยให้เกมหลายผู้เล่นที่มีอำนาจจากเซิร์ฟเวอร์รู้สึกเรียบและตอบสนอง
การตั้งค่า
เมื่อโมเดลอำนาจของเซิร์ฟเวอร์ต้องการเทคโนโลยีอื่นๆ ของเอนจินบางอย่างให้ทำงานอย่างถูกต้อง คุณต้องตั้งค่าคุณสมบัติดังต่อไปนี้บนวัตถุ Workspace ใน Explorer:
- Workspace.NextGenerationReplication จะต้องถูกเปิดใช้งาน
- Workspace.PlayerScriptsUseInputActionSystem จะต้องถูกเปิดใช้งาน
- Workspace.SignalBehavior จะต้องเป็น Deferred
- Workspace.UseFixedSimulation จะต้องถูกเปิดใช้งาน
- Workspace.StreamingEnabled จะต้องถูกเปิดใช้งาน
- Workspace.AuthorityMode จะต้องเป็น Server (จำเป็นต้องตั้งค่าทั้งหมดข้างต้นก่อน)
แนวคิด
ระบบอำนาจของเซิร์ฟเวอร์ดำเนินการตามแนวคิดหลักไม่กี่ข้อดังนี้
การคาดการณ์ของไคลเอนต์
ผ่าน การคาดการณ์ของไคลเอนต์ ไคลเอนต์จะจำลองไปข้างหน้าหลายเฟรมจากสถานะเซิร์ฟเวอร์ที่ทราบล่าสุดเพื่อตอบสนองต่อผลของการป้อนข้อมูลของผู้เล่นในทันที สิ่งนี้จะซ่อนการหน่วงเวลาในการป้อนข้อมูล แต่การคาดการณ์อาจถูกค้นพบว่าผิดในภายหลัง (client misprediction) และดังนั้นจึงเรียกร้องให้มีการแก้ไข ไคลเอนต์พยายามจำลองไปข้างหน้าพอสมควรจากสถานะเซิร์ฟเวอร์ที่มีอำนาจล่าสุดเพื่อให้การป้อนข้อมูลของมันส่งถึงเซิร์ฟเวอร์ที่เฟรมที่ตั้งใจไว้ จำนวนเฟรมที่จะถูกคาดการณ์โดยไคลเอนต์จะขึ้นอยู่กับความหน่วงเวลาที่ย้อนหลังระหว่างไคลเอนต์และเซิร์ฟเวอร์
การคาดการณ์ผิดของไคลเอนต์
เมื่อไคลเอนต์ได้รับสถานะที่มีอำนาจจากเซิร์ฟเวอร์ มันจะตรวจสอบสถานะนั้นกับบันทึกประวัติว่ามันได้คาดการณ์ไว้ในท้องถิ่นสำหรับเฟรมนั้น เมื่อมีความแตกต่างระหว่างสิ่งที่ไคลเอนต์ คาดการณ์ กับสิ่งที่เซิร์ฟเวอร์ทำจริงๆ สิ่งนี้ถือเป็น การคาดการณ์ผิด การคาดการณ์ผิดอาจเกิดขึ้นจากหลายสาเหตุรวมถึงการเปลี่ยนแปลงในความหน่วงเวลาในเครือข่าย ผู้เล่นคนอื่นทำในลักษณะที่ไคลเอนต์ไม่คาดคิด เกมที่เรียกใช้ลอจิกเฉพาะบนเซิร์ฟเวอร์ ฯลฯ
หากสถานะที่มีอำนาจแตกต่างจากสถานะที่คาดการณ์ของไคลเอนต์ ไคลเอนต์จะต้อง rollback and resimulate.
การรีเซ็ตและการจำลองใหม่
เมื่อไคลเอนต์ตรวจพบ การคาดการณ์ผิด มันจะต้องรีเซ็ตให้ตรงกับสถานะที่มีอำนาจของเซิร์ฟเวอร์และจากนั้นจำลองใหม่เพื่อตั้งกลับไปยังเฟรมที่คาดการณ์ของตน ขึ้นอยู่กับความหน่วงเวลาในเครือข่าย ไคลเอนต์จะพยายามจำลองไปข้างหน้าให้พอดีจากสถานะเซิร์ฟเวอร์ที่มีอำนาจล่าสุดเพื่อให้การป้อนข้อมูลของมันส่งถึงเซิร์ฟเวอร์ที่เฟรมที่ตั้งใจไว้
โดยสรุป ไคลเอนต์:
- รับ สถานะที่มีอำนาจ จากเซิร์ฟเวอร์และเปรียบเทียบกับ สถานะที่คาดการณ์ ของตนเอง
- หากการคาดการณ์ของไคลเอนต์ไม่ถูกต้อง:
- ไคลเอนต์จะรีเซ็ตไปยังสถานะที่มีอำนาจล่าสุดที่ได้รับจากเซิร์ฟเวอร์
- ไคลเอนต์จะจำลองใหม่จากสถานะที่มีอำนาจไปยังสถานะที่คาดการณ์ โดยการนำการป้อนข้อมูลในพื้นที่ใดๆ ที่นำกลับมาใช้ใหม่
การดำเนินการ
ความเป็นเจ้าของและการคาดการณ์เครือข่าย
ในโมเดลอำนาจของเซิร์ฟเวอร์ คุณสามารถเก็บวัตถุเกมหลักที่มีเจ้าของเซิร์ฟเวอร์โดยไม่ต้องใช้ต้นทุนการหน่วงเวลาในการป้อนข้อมูลซึ่งมักเกี่ยวข้องกับการมีเจ้าของเซิร์ฟเวอร์ สิ่งต่างๆ เช่น รถยนต์ ตัวละครของผู้เล่น หรือวัตถุที่มีความสำคัญต่อการเล่นสามารถคงอยู่ได้โดยมีเจ้าของเซิร์ฟเวอร์ แม้ว่าจะมีการโต้ตอบกับผู้เล่นคนอื่น
โดยค่าเริ่มต้น Roblox จะคาดการณ์คุณสมบัติด้วย การเข้าถึงการจำลอง โดยอยู่ใกล้กับผู้เล่นในท้องถิ่น Character แต่หากคุณต้องการควบคุมที่มีความละเอียดมากขึ้น คุณสามารถบังคับการคาดการณ์ของอินสแตนซ์โดยการเปิดหรือปิดด้วย RunService:SetPredictionMode().
การซิงค์การจำลอง
ในโมเดลอำนาจของเซิร์ฟเวอร์ ไคลเอนต์และเซิร์ฟเวอร์จะต้องดำเนินการจำลองหลัก และการจำลองของไคลเอนต์ต้องสามารถ rollback and resimulate ได้เมื่อเกิด การคาดการณ์ผิด เพื่อเปิดใช้งานสิ่งนี้ เขียนลอจิกพื้นฐานของคุณภายในฟังก์ชันที่ผูกผ่าน RunService:BindToSimulation() ใน ModuleScript ที่ถูกเริ่มต้นในทั้งไคลเอนต์และเซิร์ฟเวอร์

ในระหว่างการจำลองใหม่ Roblox จะทำการรันฟังก์ชันที่ผูกเข้ากับการจำลองผ่าน BindToSimulation() การประมวลผลการป้อนข้อมูลของผู้เล่น การโต้ตอบกับวัตถุฟิสิกส์ที่ซิงค์ และการอัปเดตสถานะหลักของเกมควรต้องอยู่ภายในฟังก์ชันที่ผูกเข้าดังกล่าว
ModuleScript ที่มีชื่อว่า Simulation ใน ReplicatedStorage:
การจำลอง
local RunService = game:GetService("RunService")
local Players = game:GetService("Players")
local Simulation = {}
Simulation.Initialize = function()
RunService:BindToSimulation(function(deltaTime)
-- อ่านการป้อนข้อมูลของผู้เล่น
-- อัปเดตสถานะของเกม
end)
end
return Simulation
การซิงค์สถานะด้วยแอตทริบิวต์
Roblox จะซิงค์คุณสมบัติทั้งหมดที่มี การเข้าถึงการจำลอง บนอินสแตนซ์ที่คาดการณ์ได้โดยอัตโนมัติ สำหรับข้อมูลที่กำหนดเอง แอตทริบิวต์ เป็นวิธีหลักในการซิงค์อินสแตนซ์ที่ถูกทำเครื่องหมายว่าเป็นคาดการณ์ได้; บนอินสแตนซ์ดังกล่าว ทุกความไม่ตรงกันในค่าแอตทริบิวต์ระหว่างแหล่งที่มาของความจริงของเซิร์ฟเวอร์และการคาดการณ์ของไคลเอนต์จะก่อให้เกิด rollback and resimulation.
ข้อจำกัดของแอตทริบิวต์
เพื่อให้ถูกจำลอง บทแอตทริบิวต์ต้องตรงตามข้อกำหนดทั้งหมดต่อไปนี้:
- ต้องอยู่ในบรรดาแอตทริบิวต์ 64 แรกใน Instance ของมัน
- ชื่อของมันต้องมีความยาวไม่เกิน 50 ตัวอักษร
- หากเป็นแอตทริบิวต์ประเภทสตริง ค่าของมันต้องมีความยาวไม่เกิน 50 ตัวอักษร
การเข้าถึงการจำลอง
คุณสมบัติและวิธีการหลายอย่างในเอนจิน API อ้างถึงป้าย การเข้าถึงการจำลอง ตัวอย่างเช่น BasePart.CFrame คุณสมบัติที่มีป้ายนี้จะถูกคาดการณ์โดยระบบอำนาจของเซิร์ฟเวอร์ นอกจากนี้เพียงแต่คุณสมบัติและวิธีที่มีป้ายนี้เท่านั้นที่สามารถเข้าถึงได้ภายในฟังก์ชันที่ผูกด้วย RunService:BindToSimulation().
การกระทำการป้อนข้อมูล
ในเกมที่มีอำนาจจากเซิร์ฟเวอร์ วิธีหลักที่ไคลเอนต์สามารถทำให้สถานะของเกมเปลี่ยนแปลงได้คือผ่าน ระบบการกระทำการป้อนข้อมูล การป้อนข้อมูลเหล่านี้จะถูกส่งไปยังเซิร์ฟเวอร์และถูกเล่นซ้ำระหว่างการจำลองใหม่บนไคลเอนต์ ดังนั้น InputActions ควรใช้สำหรับ การป้อนข้อมูลทั้งหมดที่มีผลกระทบต่อการจำลองหลัก และควรตรวจสอบให้แน่ใจว่าเป็นค่าใช้จ่ายก่อนที่จะถูกประมวลผล
โปรดทราบว่า InputContexts จะต้องเป็นลูกของ Player เพื่อให้เอนจินทราบว่าผู้ใดเป็นเจ้าของ InputContext หนึ่งในวิธีการคือการเพิ่ม InputContexts ของคุณไปยังโฟลเดอร์ใต้ ReplicatedStorage และใช้ Script ภายใต้ ServerScriptService เพื่อทำสำเนาของ InputContexts ต่อผู้เล่น:

InputSetup
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local InputsFolder = ReplicatedStorage:WaitForChild("Inputs")
local function onPlayerAdded(player)
local clone = InputsFolder:Clone()
clone.Parent = player
end
Players.PlayerAdded:Connect(onPlayerAdded)
for _, player in Players:GetPlayers() do
onPlayerAdded(player)
end
โดยใช้รูปแบบนี้ คุณสามารถอ่าน InputActions สำหรับผู้เล่นทั้งหมดใน RunService:BindToSimulation() ทั้งในไคลเอนต์และเซิร์ฟเวอร์เพื่อลงบันทึกข้อมูลเดียวกันสำหรับเฟรมเดียวกัน และบันทึกป้อนข้อมูลของเฟรมก่อนหน้าใน แอตทริบิวต์ เช่นเพื่อกระตุ้นให้ตัวละครวิ่งเมื่อการกระทำ RunAction ถูกสร้างขึ้น
โปรดทราบว่าหากคุณต้องการเขียนข้อมูลกำหนดเองลงใน ระบบการกระทำการป้อนข้อมูล คุณควรใช้ฟังก์ชันที่เชื่อมต่อกับ RunService.RenderStepped หรือ RunService:BindToRenderStep() ไม่ใช่ RunService:BindToSimulation() การยิง InputAction ใน BindToSimulation() อาจทำให้ไคลเอนต์ผลิตผลลัพธ์ที่ไม่ถูกต้องในระหว่างการจำลองใหม่
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
local Workspace = game:GetService("Workspace")
RunService:BindToRenderStep("CameraInput", Enum.RenderPriority.Last.Value, function()
-- ส่งเวกเตอร์ไปข้างหน้าของกล้องของไคลเอนต์ไปยังเซิร์ฟเวอร์ผ่าน InputAction
local cameraForwardInputAction = Players.LocalPlayer.PlayContext.CameraForward
local cameraForwardVector = Workspace.CurrentCamera.CFrame.LookVector
cameraForwardInputAction:Fire(cameraForwardVector)
end)
เหตุการณ์รีโมท
เหตุการณ์รีโมท ยังสามารถถูกใช้ภายในโมเดลอำนาจของเซิร์ฟเวอร์เพื่อช่วยให้การสื่อสารอย่างเลือกสรรระหว่างไคลเอนต์และเซิร์ฟเวอร์ ตัวอย่างเช่น เซิร์ฟเวอร์สามารถใช้เหตุการณ์รีโมทเพื่อกระจายข้อมูลเกี่ยวกับผู้เล่นที่ทำคะแนนหรือเก็บวัตถุ และไคลเอนต์สามารถใช้เหตุการณ์รีโมทเป็น API ทางเลือกในการส่งการป้อนข้อมูลไปยังเซิร์ฟเวอร์ เช่น สำหรับการกดปุ่มหรือการแตะวัตถุในโลก 3D
การเคลื่อนไหว เสียง และเอฟเฟกต์
เอฟเฟกต์ที่อยู่ด้านไคลเอนต์ เช่น การเคลื่อนไหวและเสียง จะต้องเขียนโดยรู้ว่าการจำลองของไคลเอนต์เป็นเพียงการคาดการณ์ของสถานะที่มีอำนาจจากเซิร์ฟเวอร์ BindToSimulation() จะจำกัดสิ่งที่คุณสมบัติและวิธีการสามารถเรียกใช้งานจากภายในฟังก์ชันที่ผูกไว้เพื่อช่วยแนะแนวให้คุณเขียนเฉพาะไปยังสถานะการจำลองที่ซิงค์ การแสดงผลลัพธ์ของการจำลองนี้ การกระตุ้นเอฟเฟกต์และเสียง ฯลฯ ควรทำในฟังก์ชันแยกที่เชื่อมต่อกับ RenderStepped ที่อ่านผลลัพธ์ของการจำลองและกระตุ้นเอฟเฟกต์ที่ต้องการ
คำแนะนำเพิ่มเติมเกี่ยวกับการแสดงการจำลองที่คาดการณ์ไว้นั้นอยู่ในคู่มือ เทคนิคขั้นสูง.
โครงการตัวอย่าง
นอกเหนือจากเอกสารนี้แล้ว เทมเพลตต่อไปนี้สามารถช่วยให้คุณเริ่มต้นได้:


