FiveM Network ID คืออะไร
FiveM Network ID หรือ Net ID คือหมายเลขที่ใช้ระบุ Networked Entity เพื่อให้อ้างถึง Entity เดียวกันระหว่าง Client ต่าง ๆ และ Server ได้ เช่น รถ, Ped หรือ Object ที่ถูก Synchronize ผ่านระบบ Network ของ FiveM
ตัวอย่าง Player กำลังขับรถอยู่
local ped = PlayerPedId()
local vehicle =
GetVehiclePedIsIn(
ped,
false
)
ตัวแปร vehicle คือ Entity Handle ฝั่ง Client
หากต้องการส่งรถคันนี้ไปให้ Server หรือ Client คนอื่นรู้จัก ควรแปลงเป็น Network ID
local netId =
NetworkGetNetworkIdFromEntity(
vehicle
)
จากนั้นสามารถส่ง
TriggerServerEvent(
'garage:store',
netId
)
แนวคิดหลักคือ
Entity Handle
↓
Network ID
↓
Network
↓
อีก Client / Server
↓
Entity ของเครื่องนั้น
นี่คือเหตุผลที่ Network ID เป็นพื้นฐานสำคัญมากของระบบ Vehicle, Ped, Object, OneSync และ Multiplayer Entity ใน FiveM
① FiveM Network ID คืออะไร
Network ID คือ Identifier ของ Networked Entity
เช่น
Vehicle
Ped
Object
เมื่อ Entity ถูก Synchronize ผ่าน Network Entity นั้นจะมี Network ID สำหรับใช้อ้างถึง Entity เดียวกันข้ามเครื่อง
ตัวอย่าง
รถตำรวจหนึ่งคัน
↓
Network ID = 215
Client หลายคนสามารถใช้ Network ID 215 เพื่ออ้างถึง Network Entity เดียวกันได้ ตราบใดที่ Entity นั้นยังมีชีวิตอยู่และอยู่ใน Scope ที่เกี่ยวข้อง
② Network ID กับ Entity Handle ต่างกันอย่างไร
นี่คือสิ่งที่ต้องเข้าใจมากที่สุด
Entity Handle
=
Local Reference
ส่วน
Network ID
=
Network Reference
สมมติรถคันเดียวกัน
Client A
Entity Handle = 145
Client B
Entity Handle = 381
Network ID = 75
Handle ไม่จำเป็นต้องเหมือนกัน
แต่ Network ID ใช้อ้างถึง Networked Entity เดียวกันระหว่างเครื่อง
③ ทำไม Entity Handle ถึงต่างกันในแต่ละ Client
เพราะ Entity Handle อ้างถึง Internal Game Representation ของเครื่องนั้น
Client A อาจเห็นรถเป็น
Handle 145
Client B อาจเห็นรถเดียวกันเป็น
Handle 381
จึงไม่ควรทำ
Client A:
vehicle = 145
↓
ส่ง 145 ให้ Client B
↓
คิดว่า Client B จะได้รถคันเดียวกัน
เพราะเลข 145 อาจหมายถึงสิ่งอื่นหรือไม่มี Entity นั้นเลยใน Client B
④ เมื่อไรควรใช้ Network ID
ใช้เมื่อจำเป็นต้องอ้างถึง Networked Entity ข้าม
Client → Server
Server → Client
Client A → Server → Client B
ตัวอย่าง
Garage
Vehicle Lock
Police Vehicle
Mission Vehicle
Delete Entity
Vehicle State
Ped Mission
Shared Object
Entity Interaction
ถ้า Logic อยู่ Client เดียวและไม่ต้องส่งข้าม Network Entity Handle อาจเพียงพอ
⑤ วิธีหา Network ID จาก Entity
ใช้
NetworkGetNetworkIdFromEntity(
entity
)
ตัวอย่าง
local ped =
PlayerPedId()
local vehicle =
GetVehiclePedIsIn(
ped,
false
)
if not DoesEntityExist(vehicle) then
return
end
local netId =
NetworkGetNetworkIdFromEntity(
vehicle
)
print(
'Network ID:',
netId
)
ตอนนี้ netId เป็น Network Reference ของ Vehicle นั้น
⑥ NetworkGetNetworkIdFromEntity คืออะไร
เป็น Native สำหรับแปลง
Entity Handle
↓
Network ID
ใช้กับ Networked Entity
ตัวอย่าง
local netId =
NetworkGetNetworkIdFromEntity(
vehicle
)
ถ้า Entity ไม่ได้เป็น Networked Entity ตาม Context ของระบบ ต้องตรวจ Architecture เพิ่มเติม
อย่าคิดว่า Entity ทุกตัวในโลกต้องมี Network ID ที่ควรส่งข้าม Network
⑦ วิธีแปลง Network ID กลับเป็น Entity
ใช้
NetworkGetEntityFromNetworkId(
netId
)
ตัวอย่าง
local entity =
NetworkGetEntityFromNetworkId(
netId
)
Flow คือ
Network ID
↓
NetworkGetEntityFromNetworkId
↓
Local Entity Handle
แต่ควรตรวจก่อนว่า Network Entity อยู่ใน Scope ของ Client
⑧ NetToVeh คืออะไร
สำหรับ Vehicle สามารถพบ Alias
NetToVeh(
netId
)
ตัวอย่าง
local vehicle =
NetToVeh(netId)
Concept เหมือนกับการแปลง Network ID กลับเป็น Vehicle Handle
มี Alias ตามประเภท Entity อื่น ๆ เช่น Ped/Object ตาม API ที่เกี่ยวข้อง
⑨ VehToNet คืออะไร
ในทางกลับกัน Vehicle Handle สามารถแปลงเป็น Net ID ด้วย Alias เช่น
VehToNet(vehicle)
Concept คือ
Vehicle Handle
↓
Network ID
คล้ายกับ
NetworkGetNetworkIdFromEntity(
vehicle
)
Developer อาจพบทั้งสองรูปแบบใน Script จาก Internet
⑩ PedToNet และ NetToPed คืออะไร
สำหรับ Ped ก็มี Conversion API ตามประเภท
Concept คือ
Ped Handle
↓
PedToNet
↓
Network ID
และ
Network ID
↓
NetToPed
↓
Ped Handle
หลักเดียวกับ Vehicle
สิ่งสำคัญคืออย่าสับสน Local Handle กับ Network Reference
⑪ Network ID ใช้ได้ทั้ง Client และ Server ไหม
ใช้เป็น Network Identifier สำหรับอ้าง Entity ข้าม Machines ได้
เอกสาร Cfx.re ระบุ Entity Network ID ใช้ได้ทั้ง Client และ Server ในระบบที่ State Awareness ทำงานตามปกติ
จึงเหมาะเป็นตัวกลางสำหรับ
Client
↔
Server
↔
Client
เมื่อสื่อสารเกี่ยวกับ Entity
⑫ Network ID เป็นเลขแบบไหน
Cfx.re ระบุว่า Entity Network ID เป็น 16-bit Integer
มันแทน Network Entity ที่มีอยู่ ณ ช่วงเวลาหนึ่ง
จุดสำคัญคือ
Network ID
ไม่ได้มีจำนวนไม่จำกัด
และ ID สามารถถูกนำกลับมาใช้ใหม่ได้หลัง Entity เดิมหมด Lifetime
⑬ Network ID เปลี่ยนระหว่าง Entity ยังมีชีวิตไหม
สำหรับ Lifetime ของ Network Entity นั้น Network ID จะไม่เปลี่ยน
ตัวอย่าง
Vehicle Spawn
↓
Net ID = 218
↓
Owner เปลี่ยน
↓
รถยังอยู่
↓
Net ID = 218
Ownership สามารถเปลี่ยนได้ แต่ Network ID ของ Entity เดิมยังคงเดิมระหว่าง Lifetime นั้น
⑭ Network ID ถูก Reuse ได้ไหม
ได้
เมื่อ Entity เดิมถูกลบ Network ID สามารถถูกนำกลับไปใช้กับ Entity ใหม่ภายหลัง
ตัวอย่าง
เวลา A:
Net ID 120
→ Vehicle A
Vehicle A ถูกลบ
เวลา B:
Net ID 120
→ อาจถูกใช้กับ Entity B
นี่คือเหตุผลว่าทำไม Network ID ไม่ควรเป็น Permanent Database ID
⑮ เก็บ Network ID ใน Database ได้ไหม
ไม่ควรใช้เป็น Persistent Identity
ตัวอย่างไม่ควรออกแบบ
database:
vehicle_network_id = 120
แล้ววันพรุ่งนี้หรือหลัง Restart คิดว่า Net ID 120 ยังหมายถึงรถคันเดิม
ควรใช้ Persistent Identifier เช่น
vehicle_id
plate
UUID
owner_id
database primary key
ตาม Architecture
⑯ Network ID กับ Database ID ต่างกันอย่างไร
Network ID
→ Runtime Networking
ส่วน
Database ID
→ Persistent Identity
ตัวอย่าง
Database Vehicle ID = 58231
อาจคงเดิมข้าม Server Restart
แต่รถ Runtime ที่ถูก Spawn ในแต่ละครั้งอาจได้
Session 1:
Net ID 51
Session 2:
Net ID 433
นี่เป็นเรื่องปกติ
⑰ Network ID กับ Plate ต่างกันอย่างไร
Plate สามารถเป็น Business Identifier ของ Vehicle ในบางระบบ
Network ID เป็น Runtime Networking Identifier
ตัวอย่าง
Plate:
ABC123
Database ID:
58231
Network ID:
184
Client Handle:
721
ทั้งสี่ค่ามีหน้าที่ต่างกัน
Developer ไม่ควรใช้แทนกันแบบสุ่ม
⑱ Network ID กับ Player Server ID เหมือนกันไหม
คำว่า Net ID อาจสร้างความสับสน เพราะใน FiveM Player Server ID ก็ถูกเรียกในเอกสารว่า NetID ในบางบริบท
แต่ต้องแยกระหว่าง
Player Server ID
กับ
Entity Network ID
ตัวอย่าง Server Event
local src = source
src คือ Player Server ID
ไม่ใช่ Network ID ของ Vehicle
⑲ Player Server ID คืออะไร
ฝั่ง Server Player มักถูกระบุด้วย
source
เช่น
RegisterNetEvent(
'example:test',
function()
local src = source
end
)
ค่า src อ้างถึง Player Connection ปัจจุบัน
ไม่ใช่ Ped Handle และไม่ใช่ Vehicle Network ID
จึงต้องแยก Identifier อย่างชัดเจน
⑳ Player Index คืออะไร
ฝั่ง Client มี Player Index สำหรับอ้าง Local Player Representation ของผู้เล่น
และสามารถแปลงระหว่าง
Server ID
↔
Player Index
ด้วย Native ที่เกี่ยวข้อง
แต่ Player Index ก็เป็น Local เช่นเดียวกับ Entity Handle ใน State Awareness
Player ที่มีอยู่บน Server อาจยังไม่มี Player Index ใน Client หนึ่ง ถ้าไม่ได้อยู่ใน Scope
㉑ Network ID กับ Player Ped เกี่ยวข้องอย่างไร
Player Ped เป็น Networked Entity
ดังนั้น Ped ของ Player สามารถมี Entity Handle และ Network ID
Concept คือ
Player
↓
Player Ped
↓
Entity Handle
↓
Network ID
แต่ Player Server ID ยังคงเป็น Identifier คนละประเภทกับ Ped Network ID
㉒ Network ID มี Entity อยู่ทุก Client ไหม
ไม่
นี่เป็นอีกจุดสำคัญมาก
Network ID อาจมีอยู่ในระบบ แต่ Entity นั้นอาจไม่ได้อยู่ใน Scope ของ Client คนหนึ่ง
ดังนั้น
มี Net ID
≠
Client นี้มี Local Entity แน่นอน
ก่อน Resolve Net ID ควรตรวจ Entity Existence ตาม Use Case
㉓ Scope คืออะไร
Scope คือบริเวณหรือชุดของ Network Entities/Players ที่ Client จำเป็นต้องรับรู้
OneSync ไม่จำเป็นต้องส่งทุก Entity ใน Server ให้ Client ทุกคน
Concept คือ
Player อยู่ใกล้ Entity
↓
Entity เข้า Scope
Player อยู่ไกล
↓
Entity ออกจาก Scope
ช่วยลด Network และ Client Processing
㉔ ทำไม Network ID บางครั้ง NetToVeh ได้ 0
หนึ่งในสาเหตุที่เป็นไปได้คือ Vehicle ยังไม่ได้อยู่ใน Scope หรือไม่มี Local Entity Representation บน Client นั้น
จึงไม่ควรทำ
local vehicle =
NetToVeh(netId)
-- ใช้ vehicle ทันที
โดยไม่ Validation
ควรตรวจก่อน
㉕ NetworkDoesEntityExistWithNetworkId คืออะไร
ใช้ตรวจว่า Network Entity ของ Net ID นั้นมีอยู่สำหรับ Context ที่เรียกหรือไม่
ตัวอย่าง
if not NetworkDoesEntityExistWithNetworkId(
netId
) then
return
end
จากนั้นค่อย
local entity =
NetworkGetEntityFromNetworkId(
netId
)
ช่วยลดการใช้ Handle ที่ไม่ Valid
㉖ ตัวอย่างรับ Vehicle Net ID อย่างปลอดภัยกว่า
RegisterNetEvent(
'vehicle:highlight',
function(netId)
if type(netId) ~= 'number' then
return
end
if not NetworkDoesEntityExistWithNetworkId(
netId
) then
return
end
local vehicle =
NetToVeh(netId)
if not DoesEntityExist(vehicle) then
return
end
-- vehicle logic
end
)
มีการตรวจทั้ง Net ID และ Entity Handle
㉗ Network ID ส่งผ่าน TriggerServerEvent ได้ไหม
ได้
ตัวอย่าง Client
local vehicle =
GetVehiclePedIsIn(
PlayerPedId(),
false
)
if not DoesEntityExist(vehicle) then
return
end
local netId =
NetworkGetNetworkIdFromEntity(
vehicle
)
TriggerServerEvent(
'garage:storeVehicle',
netId
)
Server รับ
RegisterNetEvent(
'garage:storeVehicle',
function(netId)
local src = source
-- validation
end
)
แต่ Server ต้อง Validate Net ID เพิ่ม ไม่ใช่เชื่อทันที
㉘ Network ID จาก Client เชื่อถือได้ไหม
ไม่ควรเชื่อโดยอัตโนมัติ
เพราะ Client เป็น Untrusted Environment
ผู้เล่นอาจพยายามส่ง Network ID ของ Entity อื่น
เช่น
รถของผู้เล่นคนอื่น
NPC
Object
Entity ที่ไม่ได้เกี่ยวข้อง
ดังนั้น Server ต้องตรวจว่า Action นี้ควรทำกับ Entity นั้นจริงหรือไม่
㉙ Server ควรตรวจอะไรเมื่อรับ Vehicle Net ID
ขึ้นอยู่กับระบบ แต่ตัวอย่าง Garage ควรตรวจ
Entity มีจริงไหม?
เป็น Vehicle หรือไม่?
Player อยู่ใกล้ Vehicle หรือไม่?
อยู่ใกล้ Garage หรือไม่?
Player เป็นเจ้าของรถหรือไม่?
Plate ตรงกับ Database หรือไม่?
Vehicle อยู่ใน State ที่เก็บได้หรือไม่?
Network ID เป็นเพียง Reference
ไม่ใช่ Permission
㉚ Network ID ไม่ใช่ Ownership Proof
ผู้เล่นส่ง
Net ID = 81
ไม่ได้แปลว่า
Vehicle 81 เป็นของฉัน
Server ต้องตรวจ Ownership จากระบบที่เชื่อถือได้ เช่น
Database
Server Cache
Framework Vehicle Data
อย่าใช้การที่ Client รู้ Net ID เป็นหลักฐานความเป็นเจ้าของ
㉛ Network ID ไม่ใช่ Permission
หลักเดียวกัน
รู้ Net ID
≠
มีสิทธิ์ Delete
รู้ Net ID
≠
มีสิทธิ์ Modify
รู้ Net ID
≠
เป็น Owner ใน Database
Security ต้องแยกออกจาก Networking Identifier
㉜ Network Ownership คืออะไร
Networked Entity จะมีระบบ Ownership/Control เพื่อกำหนด Client ที่รับผิดชอบการจำลอง Entity ในบางช่วง
Ownership อาจมีผลกับ
Physics
Movement
Control
Synchronization
Native Actions
แต่ Network ID ของ Entity ยังคงใช้ระบุ Entity เดิมระหว่าง Lifetime นั้น
㉝ Network ID กับ Ownership ต่างกันอย่างไร
Network ID
→ Entity ตัวไหน
ส่วน
Ownership
→ ใครกำลังควบคุม/รับผิดชอบ Network Entity
ตัวอย่าง
Net ID = 71
เวลา A:
Owner = Client 12
เวลา B:
Owner = Client 35
Net ID ยังเป็น 71
แต่ Ownership สามารถเปลี่ยนได้
㉞ Ownership Migration คืออะไร
เมื่อ Control/Ownership ของ Entity ย้ายจาก Client หนึ่งไปอีก Client หนึ่ง เรียกว่า Migration
เช่น Player ที่เคยอยู่ใกล้ Entity ออกไป
ระบบ Network อาจเลือก Owner ใหม่
ดังนั้น Script ไม่ควรสมมติว่า
คนสร้างรถ
=
Owner ตลอดไป
หัวข้อถัดไปจะเจาะ Entity Ownership โดยเฉพาะ
㉟ Network ID เปลี่ยนเมื่อ Ownership เปลี่ยนไหม
ไม่สำหรับ Entity Lifetime เดิม
นี่เป็นข้อดีของ Network ID
แม้
Client Owner
เปลี่ยน
Network Reference ของ Entity ยังไม่จำเป็นต้องเปลี่ยน
จึงสามารถใช้ Net ID อ้าง Entity ผ่าน Ownership Migration ได้ในช่วงที่ Entity นั้นยังอยู่
㊱ Network ID กับ OneSync
OneSync เป็นระบบสำคัญที่ทำให้ Entity Synchronization, Scope และ Server-side Entity Awareness ทำงานได้ใน FiveM
Network ID ถูกใช้เป็นส่วนหนึ่งของ Architecture นี้
เมื่อเขียนระบบ Multiplayer ควรเข้าใจร่วมกันว่า
Entity
↓
Network ID
↓
Scope
↓
Ownership
↓
OneSync
สิ่งเหล่านี้สัมพันธ์กัน
㊲ Server หา Entity จาก Network ID ได้ไหม
ในระบบ State Awareness/OneSync ที่รองรับ Server สามารถทำงานกับ Entity Handles และ Network IDs ตาม Server-side APIs
แนวคิดคือ
Net ID
↓
Server Entity
↓
Validation / State / Logic
แต่ต้องใช้ API ที่รองรับ Server Context
ไม่ควร Copy Client-only Native ไป Server โดยไม่ตรวจ Native Reference
㊳ State Awareness คืออะไร
State Awareness ทำให้ Server มีข้อมูลเกี่ยวกับ Entity/Player State สำหรับ Networking มากขึ้น
เอกสาร Cfx.re ระบุว่า Server-side Entity Handles มีความหมายในระบบที่ State Awareness ไม่ได้ถูกปิด
สำหรับ FiveM Server สมัยใหม่ที่ใช้ OneSync นี่เป็นพื้นฐานสำคัญของ Server-side Entity Logic
㊴ Network ID กับ Server-created Entity
เมื่อ Server สร้าง Networked Entity เช่น Vehicle ผ่าน Server-side Native ที่รองรับ Entity นั้นก็สามารถมี Network ID
Flow เช่น
Server
↓
Create Vehicle
↓
Networked Entity
↓
Network ID
↓
Relevant Clients
นี่ช่วยให้ Server เป็นผู้ Author Entity Creation ในระบบสำคัญ
㊵ ทำไม Server-created Entity น่าสนใจ
เพราะลดการพึ่ง Client ให้สร้าง Entity ที่มีผลกับระบบ
ตัวอย่าง Mission Vehicle
แทน
Client:
Spawn รถให้ฉัน
สามารถออกแบบ
Client:
ขอเริ่ม Mission
↓
Server Validate
↓
Server Create Vehicle
↓
Network ID
↓
Client ใช้รถ
ช่วยให้ Server Authority ชัดเจนขึ้น
㊶ Network ID กับ Entity Lockdown
Entity Lockdown สามารถจำกัดการสร้าง Entity จาก Client ใน Routing Bucket
หากใช้ Mode เข้มงวด ระบบอาจออกแบบให้
Client Request
↓
Server Validate
↓
Server Create Entity
↓
Network ID
↓
Client Receive
แทน Client สร้าง Entity ได้ตามใจ
เหมาะกับ Server ที่ต้องการควบคุม Entity อย่างเข้มงวด
㊷ Network ID กับ Routing Bucket
Networked Entity สามารถอยู่ใน Routing Bucket
ตัวอย่าง
Net ID 120
→ Mission Vehicle
→ Bucket 50
ผู้เล่นใน Bucket อื่นอาจไม่เห็นหรือไม่อยู่ใน Routing Context เดียวกัน
ดังนั้นถ้า Client บอกว่า Net ID ไม่พบ ต้องตรวจ Bucket/Scope ด้วย ไม่ใช่คิดว่า Entity ถูกลบเสมอไป
㊸ Network ID กับ State Bag
Entity ที่เป็น Networked Entity สามารถมี State Bag
ตัวอย่าง
Vehicle Net ID
↓
Vehicle Entity
↓
State Bag
├── fuel
├── locked
└── missionType
State Bag ช่วยผูก Custom State กับ Entity ตามระบบ Replication
ทำให้ไม่ต้อง Broadcast Event ซ้ำสำหรับ State บางประเภท
㊹ Network ID จำเป็นสำหรับ State Bag ไหม
เมื่อ Script มี Local Entity Handle สามารถเข้าถึง State ผ่าน
Entity(entity).state
ได้ตาม Runtime
Network ID มีความสำคัญเมื่อคุณต้องหา Network Entity เดียวกันจากอีก Context ก่อน
Concept คือ
Net ID
↓
Resolve Entity
↓
Entity State
แต่ State Bag API เองมี Naming/Bag Mechanism ที่จะลงรายละเอียดในหัวข้อถัด ๆ ไป
㊺ Network ID กับ Event ต่างกันอย่างไร
Network ID เป็น Data Identifier
Event เป็น Communication Mechanism
ตัวอย่าง
TriggerClientEvent(
'vehicle:update',
target,
netId
)
ใน Code นี้
TriggerClientEvent
→ ส่งข้อมูล
netId
→ บอกว่ากำลังพูดถึง Entity ตัวไหน
ทำงานร่วมกันแต่ไม่ใช่สิ่งเดียวกัน
㊻ Network ID กับ Export ต่างกันอย่างไร
Export ใช้เรียก Function ของ Resource
Network ID ใช้อ้าง Networked Entity
ตัวอย่าง
exports['garage']:StoreVehicle(
netId
)
ใน Code นี้
Export
→ API
netId
→ Entity Reference
อีกครั้ง ทั้งสองมีหน้าที่คนละส่วน
㊼ Network ID กับ Callback
Callback สามารถ Return Network ID ได้
เช่น Client ขอ Mission Vehicle
Client
↓
Server Callback
↓
Server Create Vehicle
↓
Return Net ID
↓
Client
↓
Resolve Entity
เป็น Pattern ที่มีประโยชน์ใน Server-authoritative Entity Systems
แต่ Client ต้องคำนึงว่า Entity อาจยังไม่เข้ามาอยู่ใน Scope ทันทีในบางสถานการณ์
㊽ ต้อง Wait จน Entity เข้า Scope ไหม
บาง Workflow อาจต้องรอจน Network Entity มี Local Representation
ตัวอย่าง Concept
local timeout =
GetGameTimer() + 5000
while not NetworkDoesEntityExistWithNetworkId(
netId
) do
if GetGameTimer() > timeout then
return
end
Wait(0)
end
จากนั้น
local vehicle =
NetToVeh(netId)
Timeout ช่วยไม่ให้ Thread รอไม่จบ
㊾ ทำไมไม่ควร while รอ Net ID แบบไม่มี Timeout
ตัวอย่าง
while not NetworkDoesEntityExistWithNetworkId(
netId
) do
Wait(0)
end
ถ้า Entity ไม่เคยเข้ามาใน Scope Thread อาจรอไปเรื่อย ๆ
Resource ที่ Robust ควรพิจารณา
Timeout
Cancellation
Entity Deleted
Resource Stop
ตาม Use Case
㊿ Network ID ส่ง Broadcast ได้ไหม
ได้ เช่น Server ส่ง Net ID ไปทุก Client
TriggerClientEvent(
'mission:vehicleCreated',
-1,
netId
)
แต่ไม่ได้หมายความว่า Entity จะอยู่ใน Scope ของ Client ทุกคนทันที
Client ที่ไม่เกี่ยวข้องอาจไม่จำเป็นต้องได้รับ Event นี้ด้วยซ้ำ
ควร Target เฉพาะ Player ที่ต้องใช้ข้อมูลเมื่อทำได้
51 อย่า Broadcast Net ID โดยไม่มีเหตุผล
ถ้า Mission Vehicle ใช้เฉพาะ Party 4 คน
ไม่จำเป็นต้องส่ง Event ไป Player 300 คน
สามารถส่งเฉพาะ Party Members
ช่วยลด
Network Traffic
Client Processing
Exposure ของข้อมูลที่ไม่จำเป็น
หลักคือ
ส่งเฉพาะคนที่ต้องใช้
52 Network ID กับ Security
เมื่อ Server รับ Net ID จาก Client ต้องมองว่าเป็น Untrusted Input
ตัวอย่าง
RegisterNetEvent(
'vehicle:delete',
function(netId)
-- อย่าลบทันที
end
)
ต้องตรวจก่อนว่า
ใครส่ง?
Entity อะไร?
มีสิทธิ์ไหม?
Entity อยู่ใกล้ไหม?
เป็น Entity Type ถูกต้องไหม?
Net ID ไม่ใช่ Permission Token
53 ตัวอย่าง Event Delete Vehicle ที่อันตราย
ไม่ควรทำ
RegisterNetEvent(
'vehicle:delete',
function(netId)
local entity =
NetworkGetEntityFromNetworkId(
netId
)
DeleteEntity(entity)
end
)
หากไม่มี Validation Client อาจพยายามส่ง Net ID ของ Entity อื่น
Action ที่มีผลต่อ Entity ต้องมี Authorization
54 Garage Event ควรตรวจ Plate ด้วยไหม
Network ID บอกว่าเป็น Runtime Vehicle ตัวไหน
แต่ Ownership System อาจใช้
Plate
Database Vehicle ID
Owner Identifier
ดังนั้น Garage สามารถ Resolve Entity จาก Net ID แล้วอ่าน Plate จาก Vehicle จากนั้นเทียบ Database ตาม Architecture
ช่วยเชื่อม
Runtime Entity
↔
Persistent Vehicle
เข้าด้วยกัน
55 Net ID เดิมหลังรถถูกลบใช้ต่อได้ไหม
ไม่ควร
เมื่อ Entity ถูก Delete
Network ID เดิม
ไม่ควรถูกถือว่าอ้าง Entity เดิมอีก
ในอนาคต ID นั้นสามารถถูก Reuse
ดังนั้นเมื่อ Entity Lifecycle จบ ควร Clear Runtime State ที่ผูกกับ Net ID
56 Cache Network ID ได้ไหม
ได้ระหว่าง Entity Lifetime หาก Architecture ควบคุม Lifecycle ได้
ตัวอย่าง
local missionVehicles = {}
missionVehicles[missionId] =
netId
เมื่อ Mission จบ
missionVehicles[missionId] =
nil
อย่าเก็บ Cache อย่างไม่มีกำหนดเพราะ Network ID สามารถ Reuse ได้หลัง Entity หมดอายุ
57 Network ID Debug อย่างไร
Client
local vehicle =
GetVehiclePedIsIn(
PlayerPedId(),
false
)
if not DoesEntityExist(vehicle) then
print('No vehicle')
return
end
local netId =
NetworkGetNetworkIdFromEntity(
vehicle
)
print(
'Handle:',
vehicle
)
print(
'Net ID:',
netId
)
print(
'Network exists:',
NetworkDoesEntityExistWithNetworkId(
netId
)
)
ช่วยให้เห็นความสัมพันธ์ระหว่าง Handle กับ Net ID
58 Network ID ไม่ทำงาน ตรวจอะไรบ้าง
ตรวจตามลำดับ
① Entity มีจริงหรือไม่?
② Entity เป็น Networked Entity หรือไม่?
③ Net ID ถูกต้องหรือไม่?
④ Client อยู่ใน Scope หรือไม่?
⑤ Routing Bucket ตรงหรือไม่?
⑥ Entity ถูก Delete แล้วหรือไม่?
⑦ ใช้ Native ถูก Client/Server Context หรือไม่?
⑧ Resolve ก่อน Entity Spawn เสร็จหรือไม่?
⑨ Resource ที่สร้าง Entity ยังทำงานหรือไม่?
⑩ Net ID เก่าถูก Cache นานเกินไปหรือไม่?
อย่าแก้ด้วยการเพิ่ม Wait(5000) แบบสุ่มก่อนรู้สาเหตุ
59 Checklist ก่อนใช้ FiveM Network ID
ก่อนส่ง Net ID ระหว่าง Script ให้ตรวจ
① Entity เป็น Networked Entity หรือไม่?
② ต้องข้าม Client/Server จริงไหม?
③ ถ้าไม่ ใช้ Entity Handle ได้ไหม?
④ Entity Handle ถูกแปลงเป็น Net ID แล้วหรือยัง?
⑤ Receiver อยู่ใน Scope หรือไม่?
⑥ ตรวจ NetworkDoesEntityExistWithNetworkId หรือยัง?
⑦ Resolve Net ID เป็น Local Handle ถูก Context หรือไม่?
⑧ ตรวจ DoesEntityExist หรือยัง?
⑨ Net ID มาจาก Client หรือไม่?
⑩ ถ้ามาจาก Client Validate หรือยัง?
⑪ Entity Type ถูกต้องหรือไม่?
⑫ Player มีสิทธิ์กับ Entity หรือไม่?
⑬ Ownership มีผลกับ Action หรือไม่?
⑭ Routing Bucket ถูกต้องหรือไม่?
⑮ Net ID ถูก Cache นานแค่ไหน?
⑯ Entity ถูก Delete แล้ว Clear State หรือยัง?
⑰ กำลังใช้ Net ID เป็น Database ID หรือไม่?
ข้อสุดท้ายควรตอบว่า ไม่
⑥⓪ ตัวอย่าง Network ID สำหรับมือใหม่
client.lua
RegisterCommand(
'vehnetid',
function()
local ped =
PlayerPedId()
local vehicle =
GetVehiclePedIsIn(
ped,
false
)
if vehicle == 0
or not DoesEntityExist(
vehicle
) then
print(
'You are not in a vehicle'
)
return
end
local netId =
NetworkGetNetworkIdFromEntity(
vehicle
)
print(
'Vehicle Handle:',
vehicle
)
print(
'Vehicle Network ID:',
netId
)
TriggerServerEvent(
'training:vehicleNetId',
netId
)
end,
false
)
server.lua
RegisterNetEvent(
'training:vehicleNetId',
function(netId)
local src = source
if type(netId) ~= 'number' then
return
end
print(
('Player %s sent vehicle net ID %s')
:format(
src,
netId
)
)
-- ในระบบจริง
-- ต้อง Validate Entity
-- ก่อนทำ Action สำคัญ
end
)
ตัวอย่างนี้ช่วยให้เห็น Flow
Client Vehicle
↓
Entity Handle
↓
Network ID
↓
TriggerServerEvent
↓
Server
คำถามที่พบบ่อยเกี่ยวกับ FiveM Network ID
FiveM Network ID คืออะไร
คือ Identifier สำหรับ Networked Entity ที่ใช้เพื่ออ้าง Entity เดียวกันข้าม Client และ Server ระหว่าง Lifetime ของ Entity
Network ID กับ Entity Handle เหมือนกันไหม
ไม่ Entity Handle เป็น Local Reference ส่วน Network ID เป็น Network Reference
Entity เดียวกันมี Handle เหมือนกันทุก Client ไหม
ไม่
Network ID เหมือนกันทุก Client ไหม
Network ID ใช้อ้างถึง Network Entity เดียวกันข้าม Machines ในช่วง Lifetime ของ Entity
วิธีหา Network ID จาก Entity
ใช้
NetworkGetNetworkIdFromEntity(
entity
)
วิธีหา Entity จาก Network ID
ใช้
NetworkGetEntityFromNetworkId(
netId
)
หรือ Alias เช่น NetToVeh()
Vehicle Handle แปลงเป็น Net ID อย่างไร
ใช้ NetworkGetNetworkIdFromEntity(vehicle) หรือ API Alias เช่น VehToNet(vehicle)
Network ID เปลี่ยนเมื่อ Owner เปลี่ยนไหม
ไม่ในช่วง Lifetime ของ Entity เดิม แม้ Network Ownership สามารถ Migration ได้
Network ID ถูก Reuse ได้ไหม
ได้หลัง Entity เดิมหมด Lifetime
Network ID เก็บใน Database ได้ไหม
ไม่ควรใช้เป็น Persistent ID
Network ID เป็นกี่ Bit
เอกสาร Cfx.re ระบุ Entity Network ID เป็น 16-bit Integer
มี Net ID แล้ว Entity ต้องอยู่ใน Client ไหม
ไม่ Entity อาจอยู่นอก Scope ของ Client
ตรวจว่า Net ID มี Entity ไหม
ใช้ API เช่น
NetworkDoesEntityExistWithNetworkId(
netId
)
ตาม Context
Network ID ส่งผ่าน Event ได้ไหม
ได้ และเป็นวิธีที่เหมาะกว่าการส่ง Local Entity Handle เมื่อต้องข้ามเครื่อง
Network ID จาก Client เชื่อถือได้ไหม
ไม่ควร Client Input ต้องถูก Validate Server-side ก่อน Action สำคัญ
Network ID คือ Player Source ไหม
ไม่ Entity Network ID กับ Player Server ID เป็นคนละ Identifier
Network ID เกี่ยวกับ OneSync ไหม
เกี่ยวโดยตรงกับ Networked Entity, Scope, Ownership และ State Awareness
Routing Bucket มีผลไหม
มี เพราะ Entity และ Player ใน Routing Context ต่างกันอาจไม่อยู่ใน Scope เดียวกัน
Network ID กับ State Bag เกี่ยวกันไหม
State Bags สามารถผูกกับ Networked Entity และใช้ Replicate Custom State ของ Entity ได้
สรุป FiveM Network ID คืออะไร
FiveM Network ID คือหมายเลขสำหรับอ้างถึง Networked Entity เดียวกันระหว่าง Client และ Server ในช่วง Lifetime ของ Entity
สิ่งที่ต้องจำที่สุดคือ
Entity Handle
=
Local
แต่
Network ID
=
Network Reference
ดังนั้นถ้า Client A มีรถ
Handle = 120
ไม่ควรส่ง 120 ไป Client B แล้วคาดว่าจะเป็นรถคันเดียวกัน
ควรทำ
Client A Entity Handle
↓
NetworkGetNetworkIdFromEntity
↓
Network ID
↓
Network
↓
Client B
↓
NetworkGetEntityFromNetworkId / NetToVeh
↓
Client B Local Handle
อีกเรื่องสำคัญคือ Network ID ไม่ใช่ Persistent ID
เอกสาร Cfx.re ระบุ Network ID เป็น 16-bit Integer และสามารถถูก Reuse หลัง Entity เดิมหมด Lifetime แม้ ID จะไม่เปลี่ยนระหว่าง Lifetime ของ Entity เดิมก็ตาม
ดังนั้น Database ควรใช้
Vehicle ID
Plate
UUID
Owner ID
หรือ Persistent Identifier ของระบบเอง
ไม่ใช่ Network ID
และอย่าลืมว่า Network ID หนึ่งอาจยังไม่มี Local Entity อยู่ใน Client หาก Entity นั้นอยู่นอก Scope ดังนั้นควรตรวจ Existence ก่อน Resolve และใช้งาน
สำหรับคนที่เรียน FiveM Developer กับ comsiam ให้จำว่า Network ID มีหน้าที่บอกว่าเรากำลังพูดถึง Network Entity ตัวไหน ไม่ได้บอกว่าใครเป็นเจ้าของ ใครมีสิทธิ์แก้ไข หรือ Entity นั้นต้องอยู่ใน Scope ของทุก Client
เมื่อเข้าใจจุดนี้แล้ว คุณจะพร้อมสำหรับหัวข้อถัดไปของ comsiam คือ FiveM Entity Ownership คืออะไร ซึ่งจะอธิบายว่า Networked Entity ถูกควบคุมโดยใคร Ownership ย้ายได้อย่างไร และเหตุใดบางครั้ง Native ที่สั่ง Entity จาก Client หนึ่งจึงทำงาน แต่จากอีก Client กลับไม่ทำงาน
Comments
Post a Comment