FiveM Entity Ownership คืออะไร
FiveM Entity Ownership คือระบบที่กำหนดว่า Client ใดกำลังรับผิดชอบการควบคุมและ Synchronize Networked Entity ในช่วงเวลาหนึ่ง เช่น Vehicle, Ped หรือ Object ที่อยู่ในระบบ Network ของ FiveM
ตัวอย่างรถหนึ่งคันอาจมี
Network ID = 125
แต่ขณะหนึ่ง Player A อาจเป็น Network Owner
Vehicle
↓
Network ID 125
↓
Owner = Client A
เมื่อ Player A ออกจากพื้นที่ Ownership สามารถย้ายไป Client B ได้
Vehicle
↓
Owner A
↓
A ออกจาก Scope
↓
Ownership Migration
↓
Owner B
สิ่งสำคัญมากคือ Entity Ownership ไม่ได้หมายถึงความเป็นเจ้าของรถใน Database
Network Owner หมายถึงผู้ที่กำลังรับผิดชอบด้าน Network Simulation ของ Entity ไม่ได้หมายความว่า Player คนนั้นเป็นเจ้าของรถตามระบบ Garage หรือมี Permission ทำอะไรก็ได้กับ Entity
① FiveM Entity Ownership คืออะไร
Networked Entity ต้องมีระบบจัดการว่าใครเป็นผู้ Synchronize State บางส่วนของ Entity
เช่น
ตำแหน่ง
Movement
Physics
Vehicle Behavior
Ped Behavior
Client ที่รับหน้าที่นี้เรียกว่า Network Owner ในบริบททั่วไป
Concept คือ
Networked Entity
↓
Network Owner
↓
ส่ง Sync State
↓
Server
↓
Relevant Clients
ระบบ OneSync เป็นส่วนสำคัญในการจัดการสิ่งเหล่านี้
② Entity Ownership มีเฉพาะ Networked Entity หรือไม่
แนวคิด Network Ownership เกี่ยวข้องกับ Entity ที่ถูก Network
เช่น
Networked Vehicle
Networked Ped
Networked Object
Local Entity ที่สร้างเพื่อแสดงเฉพาะ Client เดียวไม่จำเป็นต้องมี Ownership แบบ Multiplayer ในลักษณะเดียวกัน
ดังนั้นก่อนพูดเรื่อง Owner ต้องถามก่อนว่า
Entity เป็น Networked หรือ Local?
③ Entity Handle กับ Ownership ต่างกันอย่างไร
Entity Handle คือ Local Reference
local vehicle =
GetVehiclePedIsIn(
PlayerPedId(),
false
)
ส่วน Ownership คือ
Client ไหนกำลังเป็น Network Owner
รถคันเดียวอาจมี
Client A Handle = 154
Client B Handle = 621
Network ID = 80
Owner = Client A
Handle, Network ID และ Owner จึงเป็นคนละข้อมูลกัน
④ Network ID กับ Ownership ต่างกันอย่างไร
จำง่าย ๆ ว่า
Network ID
=
Entity ตัวไหน
ส่วน
Entity Ownership
=
ใครกำลังควบคุม Network Entity นั้น
ตัวอย่าง
Net ID 80
Owner = Player A
ต่อมา
Net ID 80
Owner = Player B
Network ID ยังเป็น Entity เดิม แต่ Owner เปลี่ยนได้
⑤ Ownership เปลี่ยนได้ไหม
ได้
นี่เรียกว่า Ownership Migration
FiveM/OneSync สามารถเปลี่ยนผู้ควบคุม Network Entity ตามสถานการณ์ เช่น
Player เคลื่อนที่ออกไป
Entity ออกจาก Scope
Owner Disconnect
Client ใหม่เหมาะสมกว่าในการควบคุม Entity
ดังนั้น Script ไม่ควรคิดว่า
Client ที่สร้าง Entity
=
Owner ตลอดชีวิต Entity
⑥ Ownership Migration คืออะไร
สมมติ Player A อยู่ใกล้ Vehicle
Vehicle
↓
Owner A
Player A ขับออกจากพื้นที่หรือออกนอก Scope ของ Entity
ระบบอาจ
Disown / Migrate
↓
เลือก Client ที่เหมาะสม
↓
Owner B
Cfx.re ระบุว่า Entity ที่ออกนอก Range สามารถถูก Culled และ Migrated/Disowned ได้
จึงเป็น Behavior ปกติของ OneSync
⑦ Scope เกี่ยวกับ Ownership อย่างไร
OneSync ใช้ Scope/Culling เพื่อลด Entity ที่ Client ไม่จำเป็นต้องรับรู้
เมื่อ Entity ออกจาก Scope ของ Owner เดิม
Entity
↓
Out of Scope
↓
Owner เดิมอาจไม่ควบคุมต่อ
Ownership จึงสามารถเปลี่ยน
นี่เป็นเหตุผลหนึ่งที่ Entity Control ใน FiveM ไม่ควรถูกผูกกับ Player คนเดียวแบบถาวร
⑧ Culling คืออะไร
Culling คือการลด Network State ที่ Client ไม่จำเป็นต้องได้รับ
ตัวอย่าง
Player อยู่ไกล Entity มาก
↓
Entity ไม่อยู่ใน Focus Area
↓
ไม่จำเป็นต้องมี Local Entity บน Client
OneSync Documentation ปัจจุบันระบุ Focus Zone เริ่มต้นประมาณ 424 Units ในบริบทของ Player/Entity Culling
ระบบนี้ช่วยลด Network และ Client Processing
⑨ NetworkGetEntityOwner คืออะไร
FiveM มี Native
NetworkGetEntityOwner(
entity
)
สำหรับตรวจ Network Owner ของ Entity ตาม Context ที่รองรับ
Client สามารถใช้ Pattern เช่น
local owner =
NetworkGetEntityOwner(entity)
if owner == PlayerId() then
print('I own this entity')
end
มีประโยชน์กับ Logic ที่ควรทำเฉพาะ Client ที่เป็น Owner
⑩ ตัวอย่างตรวจว่าเราเป็น Owner หรือไม่
local vehicle =
GetVehiclePedIsIn(
PlayerPedId(),
false
)
if not DoesEntityExist(vehicle) then
return
end
local owner =
NetworkGetEntityOwner(vehicle)
if owner == PlayerId() then
print(
'This client owns the vehicle'
)
end
แต่ Owner อาจเปลี่ยนหลังจาก Check ได้
ดังนั้นอย่าใช้ Check ครั้งเดียวแล้วถือว่าจริงตลอดไป
⑪ Ownership สามารถเปลี่ยนเร็วได้ไหม
ได้
Cfx.re ระบุในตัวอย่าง Server-created Entity ว่า Owner สามารถเปลี่ยนอย่างรวดเร็ว หากมี Clients หลายคนอยู่ใกล้ Entity ขณะสร้าง
ดังนั้น Code ประเภท
ตรวจ Owner
↓
Wait นาน
↓
ทำ Action
อาจไม่สามารถรับประกันว่า Client ยังเป็น Owner อยู่ตอน Action ทำงาน
⑫ Owner เปลี่ยนหลัง Check ได้อย่างไร
ตัวอย่าง
if NetworkGetEntityOwner(entity)
== PlayerId() then
Wait(2000)
-- Owner อาจเปลี่ยนแล้ว
end
ระหว่าง Wait(2000)
Player อาจเคลื่อนที่หรือ Networking State เปลี่ยน
ถ้า Ownership สำคัญกับ Action ควรตรวจใหม่ก่อนทำงานตาม Use Case
⑬ Entity Owner กับ Database Owner เหมือนกันไหม
ไม่เหมือนกันโดยเด็ดขาด
สมมติ Database บอก
Vehicle ABC123
Owner = character_154
แต่ Network Owner ขณะนี้อาจเป็น
Player 37
เพราะ Player 37 กำลังขับหรืออยู่ในตำแหน่งเหมาะสมต่อ Network Simulation
ดังนั้น
Network Owner
≠
Vehicle Legal Owner
⑭ อย่าใช้ Network Owner เป็น Vehicle Ownership Permission
ไม่ควรเขียน Logic เช่น
ถ้าเป็น Network Owner
→ ขายรถได้
เพราะ Player ที่กำลังขับรถของคนอื่นอาจกลายเป็น Network Owner ได้
การขาย/เก็บ/โอนรถต้องตรวจ
Plate
Database Vehicle ID
Character Identifier
Database Ownership
ตามระบบ Garage จริง
⑮ Entity Owner ไม่ใช่ Admin Permission
เช่นเดียวกัน
เป็น Network Owner
ไม่ได้หมายความว่า Player มี Permission
Delete
Sell
Transfer
Modify
Give Reward
Security Permission ต้องตรวจ Server-side แยกต่างหาก
⑯ Entity Ownership กับ Server Authority ต่างกันอย่างไร
Server Authority หมายถึง Server เป็นผู้ตัดสิน Business Logic สำคัญ
เช่น
Money
Inventory
Vehicle Ownership
Reward
Permission
Entity Network Ownership เป็นเรื่องการ Synchronize Game Entity
ดังนั้น Server สามารถเป็น Authority ด้าน Economy แม้ Physics ของ Vehicle จะถูก Synchronize ผ่าน Client Owner
สอง Concept นี้ไม่ขัดกัน
⑰ FiveM มี Server เป็น Network Owner ของทุก Entity ไหม
ไม่ควรมอง FiveM แบบ Multiplayer Engine ที่ Server Simulation Entity ทุกตัวตลอดเวลา
เอกสาร Cfx.re ปัจจุบันระบุว่า FiveM ไม่มี Server-based Authoritative Ownership Model แบบบาง Multiplayer Platforms ในลักษณะเดียวกัน
Network Ownership อาศัย Client Forwarding และ Ownership Events/Behavior ของ OneSync
ดังนั้นต้องออกแบบ Resource ให้เหมาะกับระบบ FiveM จริง
⑱ Server-created Entity แปลว่า Server เป็น Owner ตลอดไหม
ไม่จำเป็น
Server สามารถสร้าง Entity ผ่าน Server-side APIs
แต่เมื่อ Entity เข้าสู่โลกและมี Client ที่เหมาะสม Client สามารถเข้ามารับ Network Simulation Ownership ได้
ดังนั้น
Created by Server
≠
Network Owner เป็น Server ตลอดเวลา
นี่เป็นรายละเอียดสำคัญมาก
⑲ Orphaned Entity คืออะไร
เมื่อ Server สร้าง Entity ด้วย Server Setter แต่ยังไม่มี Client ที่เหมาะสมอยู่ใน Scope Entity อาจอยู่ในสถานะ Orphaned
Concept คือ
Server Create Entity
↓
ยังไม่มี Client ใกล้
↓
Orphaned Entity
↓
Owner = none
Cfx.re ระบุว่า NETWORK_GET_ENTITY_OWNER สามารถคืน -1 สำหรับ Orphaned Entity
⑳ Owner -1 หมายถึงอะไร
ในบริบท Server-created Orphaned Entity ตามเอกสารปัจจุบัน
NetworkGetEntityOwner(entity)
=
-1
หมายถึงยังไม่มี Client Owner ที่กำลัง Simulation Entity นั้น
เมื่อ Client ที่เหมาะสมเข้าสู่ Scope Entity จึงสามารถถูกสร้างใน Game World/Simulation และมี Ownership ตามระบบ
㉑ Orphaned Entity ยังมีอยู่บน Server ไหม
Server Setter สามารถ Register Entity กับ Server ได้ทันที
แต่ Entity อาจยังไม่มี Client Simulation
Concept คือ
Server knows entity
↓
No suitable client
↓
Orphaned
↓
Client arrives
↓
Entity becomes simulated
นี่ต่างจากการคิดว่าถ้าไม่มี Owner แล้ว Entity ต้องถูกลบทันที
㉒ RPC Native กับ Ownership เกี่ยวกันอย่างไร
Cfx.re อธิบายว่า Server-side RPC Natives บางตัวจะถูกเรียกจริงบน Client โดยทั่วไปคือ Client ที่ Own Entity
เช่น Action บางอย่างกับ Vehicle
Flow อาจเป็น
Server calls RPC native
↓
Network
↓
Entity Owner Client
↓
Native executes
ดังนั้น RPC Call มีโอกาสล้มเหลวและไม่ควรถูกมองว่ารับประกัน 100%
㉓ ทำไม Server RPC Native บางครั้งไม่ทำงาน
สาเหตุหนึ่งคือยังไม่มี Client Owner
เช่น Server Setter สร้าง Entity ในพื้นที่ไม่มี Player
Entity อยู่ Orphaned
Owner = -1
RPC Native ที่ต้องทำงานบน Client Owner จึงยังไม่มี Client ที่จะ Execute
นี่คือเหตุผลที่ Server Getter กับ Server RPC Setter อาจมี Behavior ต่างกัน
㉔ Server Setter คืออะไร
Server Setter Natives บางตัวสามารถสร้าง Entity ลง Server State ได้โดยตรง เช่นแนวทาง
CreateVehicleServerSetter(...)
Cfx.re แนะนำแนวทาง Server-created Entities สำหรับระบบหลายประเภท
โดยเฉพาะ Entity ที่ Server ต้องควบคุม Lifecycle และ Security มากขึ้น
㉕ ทำไม Server-created Entity ดีกว่า Client-created ในบางระบบ
สมมติ Mission ให้รถรางวัล
ถ้า Client เป็นผู้สร้าง
Client
↓
Spawn Vehicle
↓
บอก Server
ผู้โกงอาจพยายาม Abuse Client Spawn Flow
Architecture ที่แข็งแรงกว่าคือ
Client
↓
Request
↓
Server Validate
↓
Server Create Vehicle
↓
Network Sync
ช่วยลด Authority ที่ Client มีต่อ Entity Creation
㉖ Server-created ไม่ได้แก้ทุกปัญหา
แม้ Server จะสร้าง Vehicle
ยังต้องคิด
Ownership
Initialization
State Bags
Routing Bucket
Persistence
Cleanup
Database Ownership
Entity Lockdown
ดังนั้น Server Creation เป็นส่วนหนึ่งของ Architecture ไม่ใช่ Solution ทั้งหมด
㉗ State Bag ช่วยเรื่อง Ownership อย่างไร
State Bags มีประโยชน์มากเมื่อ Server สร้าง Entity แต่ Action บางอย่างต้องทำโดย Client Owner
ตัวอย่าง Server
local vehicle =
CreateVehicleServerSetter(
joaat('sultan'),
'automobile',
x,
y,
z,
heading
)
Entity(vehicle).state:set(
'needsSetup',
true,
true
)
Client ที่รับ Ownership สามารถเห็น State แล้วทำ Initialization
㉘ ตัวอย่าง Owner-based Initialization
Client Concept:
AddStateBagChangeHandler(
'needsSetup',
nil,
function(bagName, key, value)
if not value then
return
end
local entity =
GetEntityFromStateBagName(
bagName
)
if entity == 0 then
return
end
if NetworkGetEntityOwner(
entity
) ~= PlayerId() then
return
end
-- owner-only initialization
end
)
ช่วยให้ Action ที่จำเป็นต้องทำโดย Local Owner ถูกส่งให้ Client ที่เหมาะสม
㉙ ทำไมต้องระวัง Owner-based Initialization
เพราะ Owner สามารถเปลี่ยนระหว่าง Execution
Cfx.re แสดง Pattern ที่ต้องตรวจ State ซ้ำและให้ Owner ที่สำเร็จเป็นผู้ Clear State
เช่น
needsSetup = true
↓
หลาย Clients เห็น
↓
เฉพาะ Current Owner ทำ
↓
needsSetup = nil
ช่วยป้องกัน Initialization ซ้ำ
㉚ State Bag เหมาะกว่า TriggerClientEvent ไป Owner หรือไม่
บางกรณีใช่
ถ้า Owner สามารถเปลี่ยนก่อน Event ถึงหรือก่อน Action จบ การผูก Intent ไว้กับ Entity State สามารถ Robust กว่า
Client Owner ใหม่ยังสามารถเห็น State และทำงานต่อได้
แต่ต้องเลือกตาม Use Case
State Bag ไม่ได้แทน Event ทุกประเภท
㉛ NetworkHasControlOfEntity คืออะไร
Client-side Network APIs มี Concept การตรวจว่า Client ปัจจุบันมี Control ของ Entity หรือไม่
Developer มักใช้
NetworkHasControlOfEntity(entity)
ก่อนทำ Action ที่ต้องใช้ Network Control
Concept คือ
Do I currently control this entity?
แต่ Control สามารถเปลี่ยนได้เช่นเดียวกับ Ownership
㉜ NetworkRequestControlOfEntity คืออะไร
Client สามารถมี API สำหรับ Request Control ของ Network Entity
Concept เช่น
NetworkRequestControlOfEntity(
entity
)
แต่การ Request ไม่ได้หมายความว่าจะได้รับ Control เสมอไป
FiveM Server สามารถกรอง Control Requests และ Ownership ของ Entity อาจเปลี่ยนตาม Networking State
ดังนั้นอย่าเขียน Script โดยสมมติว่า
Request Control
=
ได้ Control ทันที 100%
㉝ อย่า Request Control ใน Infinite Loop แบบไม่จำกัด
ตัวอย่างที่ควรหลีกเลี่ยง
while not NetworkHasControlOfEntity(
entity
) do
NetworkRequestControlOfEntity(
entity
)
Wait(0)
end
ถ้า Control ไม่เคยถูกให้ Loop อาจทำงานต่อไปไม่จบ
ควรมี Timeout
㉞ ตัวอย่าง Request Control พร้อม Timeout
local timeout =
GetGameTimer() + 2000
while not NetworkHasControlOfEntity(
entity
) do
NetworkRequestControlOfEntity(
entity
)
if GetGameTimer() >
timeout then
print(
'Failed to get control'
)
return
end
Wait(0)
end
ช่วยให้ Resource ไม่ติดอยู่กับ Control Request ตลอดไป
㉟ ทำไม Request Control อาจถูก Block
FiveM มี Server Setting
sv_filterRequestControl
สำหรับควบคุม Client Control Requests
เอกสารปัจจุบันระบุ Mode ตั้งแต่ 0 ถึง 4
โดย Mode ที่เข้มขึ้นสามารถ Block Request ในสถานการณ์ต่าง ๆ จนถึงไม่อนุญาต Control Request ทั้งหมด
ดังนั้น Script ไม่ควรพึ่ง Request Control เป็น Guarantee
㊱ sv_filterRequestControl = 0
ตามเอกสารปัจจุบัน
0
=
No filtering
เป็นค่า Default ที่ระบุไว้ใน Documentation ปัจจุบัน
แต่ Server Admin สามารถปรับให้เข้มขึ้นได้ตาม Security Requirement
㊲ sv_filterRequestControl = 1 และ 2
Mode 1 และ 2 เพิ่มข้อจำกัดกับ Request Control ของ Vehicles ที่ถูก Own/Settled ตามเงื่อนไขของระบบ
รายละเอียดเกี่ยวข้องกับ Settle Timer และ Ownership State
Developer Resource จึงไม่ควรออกแบบโดยคาดว่า Control Request ทุกครั้งจะสำเร็จในทุก Server Configuration
㊳ sv_filterRequestControl = 3
Mode 3 จำกัด Control Requests มากขึ้น โดย Block Requests สำหรับ Controlled หรือ Settled Entities ตาม Documentation ปัจจุบัน
Server ที่ใช้ Setting นี้อาจทำให้ Script เก่าบางตัวที่ Request Control แบบ Aggressive ทำงานต่างจากเดิม
㊴ sv_filterRequestControl = 4
Mode 4 คือ
Disallow all control requests
ตามเอกสาร Cfx.re ปัจจุบัน
ดังนั้น Resource ที่ต้องพึ่ง Client ขอ Ownership จาก Entity อื่นตลอดเวลาอาจไม่ Compatible กับ Server ที่ตั้ง Security Mode แบบนี้
㊵ Resource ควรออกแบบอย่างไรแทน Request Control มากเกินไป
พิจารณาใช้
Server-created Entity
State Bags
Server-side Validation
Owner-aware Logic
Routing Bucket
Proper Entity Lifecycle
แทนการให้ Client ทุกคนพยายามแย่ง Control Entity
Architecture ที่ดีควรลด Ownership Fighting
㊶ Ownership Fighting คืออะไร
สมมติ Clients หลายคนทำ
Client A
→ Request Control
Client B
→ Request Control
Client C
→ Request Control
ซ้ำ ๆ กับ Entity เดียวกัน
อาจทำให้ระบบซับซ้อนและเกิด Unstable Behavior
โดยเฉพาะถ้า Script หลาย Resources ต่างคิดว่าตัวเองต้อง Own Entity
ควรออกแบบให้มี Responsibility ชัดเจน
㊷ Client ที่ใกล้ที่สุดต้องเป็น Owner เสมอไหม
ไม่ควรเขียน Business Logic โดยยึดกฎง่าย ๆ ว่า
Nearest Player
=
Owner แน่นอน
Networking Scheduler เป็นผู้จัดการ Ownership ตาม State และเงื่อนไขของระบบ
Developer ควรตรวจ Owner จริงเมื่อจำเป็น
ไม่ควรเดา Owner จาก Distance อย่างเดียว
㊸ Player ขับรถแล้วต้องเป็น Owner เสมอไหม
มักมีความสัมพันธ์ด้าน Simulation แต่ไม่ควรใช้สมมติฐานนี้เป็น Security Logic
หากต้องการรู้ Player ขับรถหรือไม่ ให้ตรวจ Gameplay State
ถ้าต้องการตรวจ Network Owner ให้ใช้ Network Ownership API
อย่าผสมสองเรื่องเข้าด้วยกัน
㊹ Network Owner Disconnect เกิดอะไรขึ้น
ถ้า Client Owner Disconnect ระบบต้องจัดการ Network Entity ต่อ
Entity สามารถ
Migrate
Become Unowned/Orphaned
ถูก Cleanup
ขึ้นกับ Entity Lifecycle, Script Ownership และ OneSync State
ดังนั้น Resource ต้องรับมือกรณี Owner หายไปได้
㊺ อย่าผูก Mission กับ Owner Player เพียงคนเดียว
สมมติ Mission Vehicle มี Owner เป็น Player 15
ไม่ควรเก็บ Logic ว่า
ถ้า Player 15 หาย
→ Mission Vehicle ใช้งานไม่ได้
Mission Identity ควรอยู่ใน Server State เช่น
missionId
vehicle database/runtime reference
network id
party
state
Network Owner เปลี่ยนได้โดยไม่ควรทำให้ Business State หาย
㊻ Network Owner กับ Script Ownership ต่างกันอย่างไร
นี่เป็น Concept ที่สับสนได้ง่าย
Network Ownership เกี่ยวกับ Client ที่ควบคุม Network Simulation
ส่วน Script Ownership/Mission Entity Lifecycle เกี่ยวกับ Script/Resource ที่ถือ Entity ตามระบบ Game/OneSync
ไม่ควรถือว่าเป็นคำเดียวกัน
Resource ระดับสูงควรแยกทั้งสอง Concept
㊼ SetEntityAsMissionEntity คือ Network Ownership ไหม
ไม่
การ Mark Entity เป็น Mission Entity เกี่ยวกับ Script/Entity Lifecycle และ Cleanup Behavior
ไม่ได้หมายความว่า Client นั้นจะเป็น Network Owner ตลอดไป
Network Ownership ยังสามารถ Migration ได้ตาม OneSync
㊽ SetEntityOrphanMode คืออะไร
Server-side OneSync มี
SetEntityOrphanMode(
entity,
mode
)
สำหรับควบคุม Server Entity Persistence Behavior เมื่อไม่มี Owner
Cfx.re แนะนำ KeepEntity Mode ใน Use Case ที่ต้องการให้ Entity ไม่ถูก Server ลบเพราะไม่มี Client Owner
ตัวอย่าง
SetEntityOrphanMode(
vehicle,
2
)
㊾ KeepEntity ทำให้ Entity อยู่ข้าม Restart ไหม
ไม่
มันเกี่ยวกับ Runtime Entity Lifecycle
ไม่ได้ทำให้ Entity กลายเป็น Database Persistent Object
ถ้า Server Restart
ข้อมูล Entity Runtime หายได้ตามระบบ
ถ้าต้องการ Spawn กลับต้องเก็บ Persistent Data เช่น
Database ID
Model
Coords
Heading
Properties
แล้วสร้างใหม่
㊿ Entity Ownership กับ Routing Bucket
Routing Bucket มีผลกับ Entity Scope
ถ้า Player และ Entity อยู่คนละ Bucket
Player
Bucket 1
Vehicle
Bucket 2
พวกเขาไม่ได้อยู่ Routing Context เดียวกัน
จึงอาจไม่มี Client Owner/Visibility ตามที่ Developerคาด
ระบบ Instance ต้องจัด Bucket ให้ถูก
51 Entity Lockdown กับ Ownership
Entity Lockdown ไม่ใช่ Ownership System โดยตรง
มันควบคุมว่า Clients สามารถสร้าง Entity ใน Routing Bucket ได้แค่ไหน
ตัวอย่าง
SetRoutingBucketEntityLockdownMode(
bucketId,
'strict'
)
strict ไม่อนุญาต Client-created Entities ใน Bucket นั้น
ช่วยสร้าง Architecture
Client
↓
Request
↓
Server
↓
Create Entity
↓
OneSync Ownership
ที่ควบคุมได้มากขึ้น
52 strict ไม่ได้หมายความว่า Server Simulation ทุก Entity
แม้ Entity Lockdown เป็น strict
มันหมายถึง Client ไม่สามารถ Author Entity Creation ใน Bucket นั้น
แต่เมื่อ Networked Entity มีอยู่ Network Simulation Ownership ยังทำงานตาม OneSync Model
จึงไม่ควรสับสน
Entity Creation Authority
กับ
Entity Network Ownership
53 Entity Ownership กับ Security
Network Owner ไม่ควรมีสิทธิ์กำหนด Business State
เช่น Client ที่ Own Vehicle ไม่ควรสามารถบอก Server ว่า
vehiclePrice = 0
vehicleOwner = me
stored = true
reward = 100000
แล้ว Server เชื่อ
Server-side Validation ยังจำเป็นเหมือนเดิม
54 Owner ส่ง Entity State มา Server เชื่อได้ไหม
Network Sync State ของ Game เป็นส่วนหนึ่งของ Networking System
แต่ Custom Business Data จาก Client ยังต้องคิดเรื่อง Trust
ตัวอย่าง
Client Owner says:
fuel = 999999
ถ้า Fuel มีผลกับ Economy หรือ Reward Server อาจต้อง Validate
การเป็น Network Owner ไม่ได้ทำให้ Client กลายเป็น Trusted Business Authority
55 Entity Ownership กับ State Bag Security
State Bag มี Replication Policy
โดยทั่วไป Entity State สามารถถูกจัดการตาม Ownership/Server Rules ที่เกี่ยวข้อง
แต่ Developer ต้องกำหนดว่า State ไหน
Presentation only
กับ State ไหน
Security critical
ข้อมูล Security-critical ควรให้ Server เป็น Authority
หัวข้อ State Bag จะลงรายละเอียดต่อไป
56 Entity Owner Debug อย่างไร
Client สามารถเริ่มจาก
local entity =
GetVehiclePedIsIn(
PlayerPedId(),
false
)
if not DoesEntityExist(entity) then
return
end
local netId =
NetworkGetNetworkIdFromEntity(
entity
)
local owner =
NetworkGetEntityOwner(
entity
)
print(
'entity:',
entity
)
print(
'net id:',
netId
)
print(
'owner:',
owner
)
print(
'my player id:',
PlayerId()
)
ช่วยดูว่า Client ปัจจุบันเป็น Owner หรือไม่
57 Entity Control ไม่ทำงานตรวจอะไร
ตรวจ
① Entity มีจริงไหม?
② เป็น Networked Entity หรือไม่?
③ อยู่ใน Scope หรือไม่?
④ Network ID ถูกต้องไหม?
⑤ Current Owner คือใคร?
⑥ Client มี Control หรือไม่?
⑦ Control Request ถูก Filter หรือไม่?
⑧ Routing Bucket ตรงไหม?
⑨ Entity เป็น Orphaned หรือไม่?
⑩ Owner เปลี่ยนระหว่าง Operation หรือไม่?
⑪ RPC Native ที่ใช้รับประกันหรือไม่?
⑫ Entity ถูก Delete แล้วหรือไม่?
อย่าแก้ทุกปัญหาด้วย Loop NetworkRequestControlOfEntity() ไม่จำกัด
58 Architecture สำหรับ Mission Vehicle ที่ดีกว่า
Flow ที่แข็งแรงกว่าอาจเป็น
Client ขอ Mission
↓
Server Validate
↓
Server Create Vehicle
↓
Server เก็บ Network ID / Mission State
↓
State Bag กำหนด Initial State
↓
Client ที่เป็น Owner ทำ Local Initialization ที่จำเป็น
↓
Server ตรวจ Result/State
↓
Ownership เปลี่ยนได้
↓
Mission ยังดำเนินต่อ
Business State ไม่ผูกกับ Owner คนใดคนหนึ่ง
59 Checklist FiveM Entity Ownership
ก่อนเขียนระบบ Network Entity ให้ตรวจ
① Entity เป็น Networked หรือ Local?
② Network ID คืออะไร?
③ Current Owner คือใคร?
④ Owner จำเป็นกับ Logic นี้จริงไหม?
⑤ Ownership เปลี่ยนได้หรือไม่?
⑥ หลัง Wait ต้องตรวจ Owner ใหม่ไหม?
⑦ Entity อยู่ใน Scope หรือไม่?
⑧ Entity เป็น Orphaned หรือไม่?
⑨ ต้องใช้ Server-created Entity หรือไม่?
⑩ Action นี้เป็น RPC Native หรือไม่?
⑪ RPC Failure ถูก Handle หรือไม่?
⑫ ต้องใช้ State Bag สำหรับ Initialization หรือไม่?
⑬ ต้อง Request Control จริงไหม?
⑭ Request Control มี Timeout หรือไม่?
⑮ sv_filterRequestControl อาจ Block หรือไม่?
⑯ Network Owner ถูกสับสนกับ Database Owner หรือไม่?
⑰ Security-critical Logic อยู่ Server หรือยัง?
⑱ Routing Bucket ถูกต้องไหม?
⑲ ต้องใช้ Entity Lockdown หรือไม่?
⑳ Cleanup/Persistence ถูกออกแบบหรือยัง?
⑥⓪ หลักจำ Entity Ownership แบบง่ายที่สุด
จำ 4 บรรทัดนี้
Network ID
=
Entity ตัวไหน
Entity Owner
=
ใครกำลังควบคุม Network Simulation
Database Owner
=
ใครเป็นเจ้าของทรัพย์สินตามระบบเซิร์ฟเวอร์
และ
Network Owner
สามารถเปลี่ยนได้
ถ้าแยก 4 Concept นี้ได้ การทำ Multiplayer Entity ใน FiveM จะง่ายขึ้นมาก
ตัวอย่างตรวจ Owner พร้อม State Bag
server.lua
local vehicle =
CreateVehicleServerSetter(
joaat('sultan'),
'automobile',
215.0,
-810.0,
30.0,
157.0
)
if vehicle == 0 then
return
end
SetEntityOrphanMode(
vehicle,
2
)
Entity(vehicle).state:set(
'vehicleNeedsInit',
true,
true
)
client.lua
AddStateBagChangeHandler(
'vehicleNeedsInit',
nil,
function(
bagName,
key,
value
)
if not value then
return
end
local entity =
GetEntityFromStateBagName(
bagName
)
if entity == 0 then
return
end
if NetworkGetEntityOwner(
entity
) ~= PlayerId() then
return
end
SetVehicleOnGroundProperly(
entity
)
Entity(entity).state:set(
'vehicleNeedsInit',
nil,
true
)
end
)
แนวคิดคือ
Server
↓
Create Vehicle
↓
Set State
↓
Entity เข้า Scope
↓
Client ได้ Ownership
↓
Owner ทำ Initialization
↓
Clear State
เหมาะกว่า Hardcode ว่า Player คนที่ขอ Spawn ต้องเป็น Owner ตลอดไป
คำถามที่พบบ่อยเกี่ยวกับ FiveM Entity Ownership
FiveM Entity Ownership คืออะไร
คือระบบที่กำหนด Client ซึ่งกำลังรับผิดชอบ Network Simulation/Control ของ Networked Entity ในช่วงเวลาหนึ่ง
Entity Owner เปลี่ยนได้ไหม
ได้ Ownership สามารถ Migration เมื่อ Scope หรือ Networking Situation เปลี่ยน
Client ที่สร้างรถเป็น Owner ตลอดไหม
ไม่ควรสมมติแบบนั้น Ownership สามารถเปลี่ยนได้
Network ID เปลี่ยนเมื่อ Owner เปลี่ยนไหม
ไม่ใน Lifetime ของ Network Entity เดิม
Network Owner คือเจ้าของรถใน Database ไหม
ไม่ เป็นคนละ Concept
Network Owner มีสิทธิ์ขายรถไหม
ไม่โดยอัตโนมัติ ต้องตรวจ Database/Server Permission
วิธีตรวจ Owner ฝั่ง Client
ใช้ Native เช่น
NetworkGetEntityOwner(
entity
)
และสามารถเทียบกับ
PlayerId()
ตาม Use Case
NetworkHasControlOfEntity คืออะไร
ใช้ตรวจว่า Client ปัจจุบันมี Network Control ของ Entity หรือไม่
Request Control ได้ไหม
มี NetworkRequestControlOfEntity() แต่ Request ไม่ได้รับประกันว่าจะสำเร็จ
ทำไม Request Control ไม่สำเร็จ
อาจเกี่ยวกับ Current Ownership, Scope หรือ Server Setting อย่าง sv_filterRequestControl
ควร Loop Request Control ไปเรื่อย ๆ ไหม
ไม่ ควรมี Timeout และ Error Handling
Orphaned Entity คืออะไร
Server-created Entity ที่ยังไม่มี Client ที่เหมาะสมรับ Simulation Ownership
Owner ของ Orphaned Entity คืออะไร
Cfx.re ระบุว่า NETWORK_GET_ENTITY_OWNER สามารถคืน -1 ในสถานะนี้
Server-created Entity เป็น Server Owner ตลอดไหม
ไม่ เมื่อมี Client ที่เหมาะสม Network Simulation Ownership สามารถอยู่กับ Client ได้
SetEntityOrphanMode ทำอะไร
ใช้ควบคุม Runtime Persistence Behavior ของ Server Entity เมื่อไม่มี Owner
KeepEntity ทำให้รถอยู่หลัง Restart ไหม
ไม่ Database Persistence เป็นอีกระบบหนึ่ง
State Bag ช่วย Ownership อย่างไร
ช่วยเก็บ Intent/State ไว้กับ Entity ทำให้ Current Owner หรือ Owner ใหม่สามารถตอบสนองต่อ State ได้ตาม Architecture
Entity Lockdown คือ Ownership หรือไม่
ไม่ เป็นระบบควบคุมการสร้าง Entity จาก Client
Routing Bucket มีผลกับ Ownership ไหม
มีผลทางอ้อมผ่าน Scope และ Routing Context ของ Player/Entity
Network Owner เชื่อถือเรื่อง Money/Inventory ได้ไหม
ไม่ Network Ownership ไม่ได้ทำให้ Client เป็น Trusted Authority ด้าน Business Logic
สรุป FiveM Entity Ownership คืออะไร
FiveM Entity Ownership คือกลไกของ Networking ที่กำหนด Client ซึ่งกำลังรับผิดชอบการควบคุมและ Synchronize Networked Entity ในช่วงหนึ่ง
ตัวอย่าง
Vehicle
↓
Net ID 125
↓
Owner A
↓
A ออกจาก Scope
↓
Ownership Migration
↓
Owner B
สิ่งสำคัญที่สุดคือ Ownership สามารถเปลี่ยนได้
ดังนั้นอย่าออกแบบ Script ว่า
คน Spawn
=
Owner ตลอดไป
และต้องแยกให้ออกระหว่าง
Network Owner
→ ผู้รับผิดชอบ Network Simulation
กับ
Database Owner
→ เจ้าของรถ/ทรัพย์สินในระบบเซิร์ฟเวอร์
รวมถึง
Server Authority
→ ผู้ตัดสิน Money, Inventory, Permission และ Business Logic
อีกประเด็นที่สำคัญคือ Server-created Entity สามารถเริ่มต้นในสถานะ Orphaned หากยังไม่มี Client เหมาะสมอยู่ใน Scope และ Cfx.re ระบุว่า NetworkGetEntityOwner() สามารถคืน -1 ในกรณีนี้
เมื่อ Client เข้ามาใกล้ Entity จึงสามารถได้รับ Ownership และทำ Simulation ต่อ
สำหรับคนที่เรียน FiveM Developer กับ comsiam การเข้าใจ Ownership จะช่วยอธิบายปัญหาหลายอย่าง เช่น ทำไม Client หนึ่งสั่ง Vehicle ได้แต่อีก Client สั่งไม่ได้ ทำไม Entity Owner เปลี่ยนหลัง Player เดินออกไป และทำไม Script ที่พยายาม NetworkRequestControlOfEntity() ตลอดเวลาจึงไม่ใช่ Architecture ที่ดี
หลักที่ควรจำจาก comsiam คือ Network Owner เป็นผู้ควบคุมการ Sync ในช่วงเวลานั้น ไม่ใช่เจ้าของข้อมูลหรือผู้มีสิทธิ์เหนือ Entity ทุกอย่าง
หัวข้อถัดไปคือ FiveM State Bag คืออะไร ซึ่งเป็นระบบสำคัญสำหรับเก็บและ Replicate Custom State ระหว่าง Server, Entity และ Clients โดยไม่ต้อง Broadcast Network Event ซ้ำ ๆ ทุกครั้งที่ State เปลี่ยน
Comments
Post a Comment