FiveM Network ID คืออะไร? ต่างจาก Entity Handle อย่างไร และใช้ Sync Entity ข้าม Client/Server แบบไหน
FiveM Network ID หรือ NetID คือหมายเลขที่ใช้ระบุ Networked Entity ข้ามระหว่าง Client และ Server เช่น Vehicle, Ped หรือ Object โดย Cfx.re ระบุว่า Network ID เป็นค่า 16-bit integer ที่แทน Entity หนึ่งในช่วงเวลาหนึ่ง และค่าจะไม่เปลี่ยนตลอด Lifetime ของ Entity นั้น แม้หมายเลขอาจถูกนำกลับมาใช้ใหม่หลัง Entity เดิมหมดอายุแล้ว.
จุดสำคัญที่สุดที่ Developer ต้องเข้าใจคือ Entity Handle กับ Network ID ไม่ใช่สิ่งเดียวกัน เพราะ Entity Handle เป็น Local Reference ของแต่ละเครื่อง ขณะที่ Network ID ถูกออกแบบให้ใช้ระบุ Entity ข้าม Clients และ Server.
Meta SEO
Meta Title: FiveM Network ID คืออะไร? NetID ต่างจาก Entity Handle อย่างไร
Meta Description: อธิบาย FiveM Network ID หรือ NetID แบบละเอียด วิธีใช้ NetworkGetNetworkIdFromEntity, NetworkGetEntityFromNetworkId, Scope, OneSync และวิธีแก้ NetID หา Entity ไม่เจอ
Focus Keyword: FiveM Network ID
Related Keywords: FiveM NetID, FiveM Entity Handle, NetworkGetNetworkIdFromEntity, NetworkGetEntityFromNetworkId, FiveM OneSync, FiveM Entity Sync
สารบัญ
① FiveM Network ID คืออะไร
Network ID คือ ID สำหรับ Networked Entity
ตัวอย่างเชิงแนวคิด:
Vehicle
Entity Handle บน Client A = 328514
Entity Handle บน Client B = 425918
Network ID = 143
Client A และ Client B อาจมี Local Entity Handle คนละเลข แต่ยังสามารถอ้างถึง Entity เดียวกันด้วย Network ID เดียวกันได้.
② Network ID มีไว้ทำอะไร
ใช้เมื่อ Resource ต้องการระบุ Entity ข้าม Context เช่น:
Client A
↓
ส่ง NetID
↓
Server
↓
ส่ง NetID
↓
Client B
แทนการส่ง Entity Handle จาก Client A ไป Client B ซึ่งไม่รับประกันว่าจะหมายถึง Entity เดียวกัน.
③ Network ID เป็นค่าถาวรหรือไม่
ไม่ใช่ Permanent ID
Cfx.re ระบุว่า Network ID สามารถถูกนำกลับมาใช้ใหม่ได้ภายหลัง แต่จะไม่เปลี่ยนระหว่าง Lifetime ของ Entity เดิม.
ดังนั้นไม่ควรเก็บ NetID เป็น Primary Key ถาวรใน Database
④ Network ID มีขนาดเท่าไร
Cfx.re ระบุว่า Entity Network ID เป็นค่า 16-bit integer.
นี่เป็นอีกเหตุผลที่หมายเลขสามารถถูก Reuse ได้หลัง Entity เดิมหมดอายุ
⑤ NetID ใช้เป็น Database ID รถได้ไหม
ไม่ควร
ถ้ารถต้องกลับมาหลัง Server Restart ควรมี Persistent ID ของระบบเอง เช่น:
vehicleDatabaseId = 1824
ส่วน NetID ใช้อ้าง Network Entity ที่กำลังมีอยู่ใน Runtime
แนวคิดจึงเป็น:
Database Vehicle ID
= ตัวตนถาวร
Network ID
= ตัวตนใน Network Runtime
Entity Handle
= Local Reference
⑥ Entity Handle คืออะไร
Cfx.re อธิบายว่า Entity Handle เป็นค่าที่อ้างถึง Internal Game Representation ของ Entity และเป็น Local ต่อ Client หนึ่งเครื่อง.
เช่น:
local vehicle = GetVehiclePedIsIn(PlayerPedId(), false)
ตัวแปร vehicle คือ Entity Handle ใน Context ของ Client เครื่องนั้น
⑦ Entity Handle เหมือนกันทุก Client ไหม
ไม่
Cfx.re ระบุชัดว่าไม่ควรคาดหวังว่า Entity เดียวกันจะมี Handle เดียวกันบน Clients ต่างเครื่อง.
ตัวอย่าง:
รถคันเดียวกัน
Client A → Handle 20482
Client B → Handle 72193
แต่สามารถมี NetID เดียวกัน
⑧ Entity Handle เปลี่ยนได้ไหม
ได้
Cfx.re ระบุว่า Entity เดิม หากถูก Recreated ใน Local หรือ Remote Context สามารถได้รับ Handle ใหม่ได้.
จึงไม่ควร Cache Handle ระยะยาวโดยไม่ตรวจว่า Entity ยังมีอยู่
⑨ Entity Handle กับ Network ID ต่างกันอย่างไร
| ค่า | ขอบเขต | ใช้ข้าม Client/Server |
|---|---|---|
| Entity Handle | Local | ไม่ควร |
| Network ID | Network | ได้ |
| Database ID | Persistent Storage | แล้วแต่ระบบ |
Cfx.re แนะนำให้ใช้ Network ID หากต้องอ้าง Entity ข้าม Machines.
⑩ จำง่ายที่สุด
Handle = Local
NetID = Network
Database ID = Persistent
ถ้าเข้าใจ 3 ตัวนี้ Developer จะลด Bug Networking ได้มาก
⑪ แปลง Entity Handle เป็น Network ID อย่างไร
ใช้:
NetworkGetNetworkIdFromEntity(entity)
Native Reference ของ Cfx.re มี Function นี้สำหรับเปลี่ยน Entity Handle เป็น Network ID.
ตัวอย่าง:
local vehicle = GetVehiclePedIsIn(
PlayerPedId(),
false
)
if vehicle ~= 0 then
local netId =
NetworkGetNetworkIdFromEntity(vehicle)
print(('NetID: %s'):format(netId))
end
⑫ ต้องตรวจ Entity ก่อนแปลงไหม
ควร
ตัวอย่าง:
if DoesEntityExist(entity) then
local netId =
NetworkGetNetworkIdFromEntity(entity)
end
เพราะการใช้ Handle ที่ Entity ถูกลบไปแล้วสามารถทำให้ Logic ของ Resource ผิดจากที่คาด
⑬ PedToNet, VehToNet ใช้ได้ไหม
Cfx.re ระบุว่ามี Alias สำหรับการแปลงประเภท Entity เช่นแนวคิด PED_TO_NET หรือ NET_TO_VEH นอกเหนือจาก Functions แบบ Generic.
แต่สำหรับ Resource ที่ต้องรองรับ Entity หลายประเภท การใช้ Generic Network ID APIs มักอ่านง่ายกว่า
⑭ ส่ง Entity Handle เข้า TriggerServerEvent ได้ไหม
ตัวเลขสามารถถูกส่งได้ในเชิงข้อมูล แต่ ไม่ควรถือว่า Server หรือ Client อีกเครื่องจะตีความ Handle ตัวนั้นเป็น Entity เดียวกัน
เพราะ Entity Handle เป็น Local Reference.
ควรส่ง:
local netId =
NetworkGetNetworkIdFromEntity(entity)
TriggerServerEvent(
'myresource:entityAction',
netId
)
แทน
⑮ แปลง Network ID กลับเป็น Entity อย่างไร
ใช้:
NetworkGetEntityFromNetworkId(netId)
Cfx.re ระบุว่า Native นี้คืน Local Entity Handle ของ Network ID ที่กำหนด.
ตัวอย่าง:
local entity =
NetworkGetEntityFromNetworkId(netId)
⑯ NetID มีแล้วแปลงเป็น Entity ได้ทันทีเสมอไหม
ไม่
Cfx.re ระบุว่า Network ID ไม่จำเป็นต้องอยู่ใน Scope ของ Client และต้องตรวจการมีอยู่ก่อนใช้งาน.
นี่เป็นหนึ่งในเรื่องสำคัญที่สุดของ OneSync
⑰ ตรวจ NetID ว่ามี Entity อยู่หรือไม่อย่างไร
ใช้ Native:
NetworkDoesEntityExistWithNetworkId(netId)
Cfx.re มี Native นี้โดยตรงสำหรับตรวจว่า Network Entity ของ ID ที่กำหนดมีอยู่ใน Context นั้นหรือไม่.
ตัวอย่าง:
if NetworkDoesEntityExistWithNetworkId(netId) then
local entity =
NetworkGetEntityFromNetworkId(netId)
end
⑱ ทำไม Network ID ถูกต้องแต่ Entity เป็น 0
หนึ่งในสาเหตุสำคัญคือ Entity ยังไม่อยู่ใน Scope ของ Client
Cfx.re เตือนว่า Network ID อาจมีอยู่ใน Server แต่ไม่ได้ Exist ใน Client Context นั้น.
ดังนั้น:
Valid NetID
ไม่ได้แปลว่า:
Entity พร้อมใช้งานบน Client นี้แล้ว
⑲ Scope คืออะไร
ใน OneSync Client ไม่จำเป็นต้อง Synchronize Entities ทั้ง Server
ระบบจะสนใจ Players และ Entities ที่เกี่ยวข้องกับ Client ตาม Network Scope ซึ่งช่วยลดปริมาณข้อมูลที่ต้องสร้างและ Synchronize.
⑳ NetID อยู่นอก Scope หมายความว่าอะไร
หมายความว่า Server หรือ Client อื่นอาจรู้จัก Entity นั้น แต่ Client ปัจจุบันยังไม่ได้มี Local Representation ของ Entity
ดังนั้น:
NetworkDoesEntityExistWithNetworkId(netId)
อาจคืน False
แม้ Entity จะยังมีอยู่บน Server.
㉑ ควร Wait จน Entity เข้า Scope ไหม
เฉพาะเมื่อ Gameplay Logic ต้องการ Entity นั้นจริง และต้องมี Timeout
ตัวอย่างแนวคิด:
local timeout = GetGameTimer() + 5000
while not NetworkDoesEntityExistWithNetworkId(netId) do
if GetGameTimer() > timeout then
return
end
Wait(100)
end
local entity =
NetworkGetEntityFromNetworkId(netId)
อย่า Loop แบบไม่มี Timeout เพราะหาก Entity ไม่มีวันเข้า Scope Resource จะรอตลอด
㉒ อย่า Wait(0) แบบไม่จำกัด
ตัวอย่างที่ไม่ควรทำ:
while not NetworkDoesEntityExistWithNetworkId(netId) do
Wait(0)
end
หาก Entity ถูกลบหรือไม่มีวันเข้า Scope Loop นี้อาจทำงานต่อโดยไม่มีจุดจบ
ควรมี:
Timeout
Cancellation
Entity lifecycle check
เสมอ
㉓ Player อยู่ไกล Entity จึงหาไม่เจอได้ไหม
ได้
OneSync ใช้ Culling/Scope เพื่อลด Entity Synchronization ที่ไม่จำเป็น และ Network ID ที่อยู่นอก Client Scope อาจไม่มี Local Entity Handle.
นี่อาจเป็น Behavior ปกติ ไม่ใช่ Bug
㉔ Routing Bucket มีผลกับ Scope ไหม
มีผลกับ Visibility/Isolation ของ Players และ Entities
หาก Player กับ Entity อยู่คนละ Routing Bucket พวกเขาอาจไม่เห็นกันตาม OneSync Routing Isolation.
ดังนั้น NetID หา Entity ไม่เจอควรตรวจ Bucket ด้วย
㉕ Entity Ownership คืออะไร
Networked Entity อาจมี Client Owner ที่รับผิดชอบ Synchronization บางส่วน และ Ownership สามารถเปลี่ยนตาม Network Conditions/Scope
OneSync Documentation อธิบายว่า Entities ที่อยู่ไกลจาก Owner สามารถถูก Culled และ Migrated/Disowned ได้.
ดังนั้นอย่าสมมติ Client คนเดิมจะเป็น Owner ตลอด Lifetime
㉖ NetID เปลี่ยนเมื่อ Owner เปลี่ยนไหม
โดยหลัก Network ID ของ Entity ไม่เปลี่ยนระหว่าง Lifetime ของ Entity แม้ Ownership/Local Handle สามารถเปลี่ยนได้.
นี่คือประโยชน์สำคัญของ NetID
㉗ Entity Handle เปลี่ยนแต่ NetID เดิมได้ไหม
ได้
Cfx.re ระบุว่า Entity เดียวกันสามารถมี Handle เปลี่ยนเมื่อถูก Recreated ใน Local Context แต่ Network ID ยังคงเป็นตัวอ้าง Network Entity ใน Lifetime นั้น.
㉘ ต้อง Request Control ทุกครั้งไหม
ไม่ควรทำเป็นสูตรตายตัว
ก่อนใช้ Network Control Native ต้องเข้าใจก่อนว่า:
Entity ใครเป็น Owner
Action ที่ทำต้องมี Control จริงหรือไม่
Logic ควรอยู่ Server หรือ Client
OneSync มี Server-side Native ที่เหมาะกว่าหรือไม่
OneSync รองรับ Server-created Entities และ Server-side Entity Operations หลายประเภท จึงไม่จำเป็นต้องโยนทุก Action ไปหา Client Owner.
㉙ Network ID เกี่ยวข้องกับ OneSync อย่างไร
OneSync เป็น Network Synchronization Engine ที่จัดการ Entity State และ Scope
Network ID เป็นตัวระบุ Network Entity ภายในระบบนี้สำหรับการอ้าง Entity ข้าม Context.
จึงมักพบคู่กันใน FiveM Resources
㉚ Server มี Entity Handle ได้ไหม
Cfx.re ระบุว่า Server-side Entity Handles ใช้งานได้เมื่อ State Awareness ไม่ได้ถูกปิด.
และ OneSync รองรับ Server-created Peds, Vehicles และ Objects.
ดังนั้น Server-side Entity Logic ปัจจุบันทำได้มากกว่าแนวทาง FiveM รุ่นเก่า
㉛ Server สร้าง Entity แล้วรับ NetID ได้ไหม
ได้ตาม Context ของ OneSync
ตัวอย่างแนวคิด:
local vehicle = CreateVehicleServerSetter(
model,
'automobile',
x,
y,
z,
heading
)
local netId =
NetworkGetNetworkIdFromEntity(vehicle)
OneSync Documentation ระบุ Server-created Entities เป็นหนึ่งใน Best Practices สำหรับระบบที่ต้องการให้ Server เป็นผู้ควบคุม Entity.
㉜ Server-created Entity ดีกว่าทุกกรณีไหม
ไม่จำเป็น
แต่สำหรับ Entity สำคัญที่ Server ต้องควบคุม การให้ Server Validate และสร้าง Entity เองมักทำให้ Authority ชัดเจนกว่า Client-created Entity
Cfx.re แนะนำ Server-created Entities เป็นแนวทางสำคัญภายใต้ OneSync.
㉝ NetID ของ Entity ที่ถูกลบเกิดอะไรขึ้น
เมื่อ Entity หมด Lifetime Network ID เดิมสามารถถูก Reuse สำหรับ Entity อื่นในอนาคตได้.
ดังนั้น Cache NetID ระยะยาวต้องมี Lifecycle Management
㉞ ต้องตรวจ Entity ทุกครั้งก่อนใช้ Cached NetID ไหม
ควรอย่างน้อยในจุดที่ Entity อาจถูกลบหรือออก Scope
เช่น:
if not NetworkDoesEntityExistWithNetworkId(netId) then
return
end
local entity =
NetworkGetEntityFromNetworkId(netId)
ช่วยป้องกันการใช้ Reference เก่า.
㉟ ใช้ Network ID กับ TriggerServerEvent อย่างไร
Client:
local vehicle =
GetVehiclePedIsIn(
PlayerPedId(),
false
)
if vehicle ~= 0 then
local netId =
NetworkGetNetworkIdFromEntity(vehicle)
TriggerServerEvent(
'garage:requestAction',
netId
)
end
Server สามารถรับ NetID แล้วตรวจ Entity ตาม OneSync Context แทนการรับ Local Handle ของ Client
㊱ Server ควรเชื่อ NetID จาก Client ไหม
ไม่ควรเชื่อโดยตรง
Cfx.re แนะนำว่า Client-triggered Events ต้อง Validate ข้อมูลฝั่ง Server เพราะ Client สามารถ Trigger Network Events และส่ง Arguments ได้.
Server ควรตรวจอย่างน้อย:
NetID มี Entity จริงหรือไม่
Entity Type ถูกหรือไม่
Player มีสิทธิ์ใช้งานหรือไม่
Entity อยู่ใน State ที่ถูกต้องหรือไม่
Action นี้อนุญาตหรือไม่
㊲ อย่าส่งแค่ NetID แล้วให้ Server ทำทุกอย่างทันที
ตัวอย่างที่ควรหลีกเลี่ยง:
RegisterNetEvent(
'garage:deleteVehicle',
function(netId)
local entity =
NetworkGetEntityFromNetworkId(netId)
DeleteEntity(entity)
end
)
โดยไม่มี Validation
Server ต้องตรวจว่า Player มีสิทธิ์จัดการ Entity นั้นก่อน ตามหลัก Server-side Validation ของ Cfx.re.
㊳ Event Direction ควรเป็นอย่างไร
Architecture ที่ดีกว่า:
Client
↓
ส่งคำขอ + NetID
↓
Server
↓
ตรวจ source + Entity + Permission + State
↓
Server ทำ Action
↓
ส่ง Result กลับ Client
NetID เป็นเพียง Reference ไม่ใช่ Permission
㊴ Network ID ใช้ร่วมกับ State Bags ได้ไหม
ได้
หลัง Client/Server Resolve NetID เป็น Entity Handle แล้ว สามารถอ่านหรือกำหนด State Bag ของ Entity นั้นได้ตาม Context
State Bags เป็น Key/Value State ที่ผูกกับ Entities ใน State Awareness Mode.
ตัวอย่าง:
local entity =
NetworkGetEntityFromNetworkId(netId)
if entity ~= 0 then
local locked =
Entity(entity).state['garage:locked']
end
㊵ ควรส่ง State ผ่าน Event หรือ State Bag
ขึ้นกับประเภทข้อมูล
Event
เหมาะกับ Action:
เปิด UI
ขอทำ Action
แจ้ง Result
State Bag
เหมาะกับ Current State:
รถล็อกหรือไม่
Entity Owner ID
Entity Mode
State Bag ช่วยผูก Runtime State กับ Entity โดยตรง.
㊶ NetID กับ State Bag Key ต่างกันอย่างไร
NetID บอกว่า:
“Entity ไหน”
State Bag บอกว่า:
“Entity นั้นมี State อะไร”
ตัวอย่าง:
NetID 143
↓
Vehicle Entity
↓
garage:locked = true
garage:owner = 1824
สองระบบจึงทำงานร่วมกันได้ดี
㊷ State Bag ช่วยลดการส่ง NetID ซ้ำได้ไหม
ในบาง Architecture ได้
หาก State ผูกกับ Entity อยู่แล้ว Client ที่มี Entity ใน Scope สามารถอ่าน State ที่ Replicate ได้ โดยไม่ต้องส่ง Request ไป Serverทุกครั้ง.
แต่ Action สำคัญยังต้องใช้ Server-side Validation
㊸ FiveM Network ID หา Entity ไม่เจอ แก้อย่างไร
ตรวจตามลำดับ:
NetID ถูกต้องหรือไม่
Entity ยังมีอยู่หรือไม่
NetID อยู่ใน Scope หรือไม่
Player กับ Entity อยู่ Routing Bucket เดียวกันหรือไม่
Entity ถูก Delete ไปแล้วหรือไม่
ใช้
NetworkDoesEntityExistWithNetworkId()หรือไม่แปลงด้วย
NetworkGetEntityFromNetworkId()หลังตรวจหรือไม่Client/Server Context ถูกหรือไม่
Cfx.re ระบุชัดว่า NetID ไม่จำเป็นต้องอยู่ใน Scope บน Client ทุกเครื่อง.
㊹ NetworkGetEntityFromNetworkId ได้ 0
ตรวจ:
if not NetworkDoesEntityExistWithNetworkId(netId) then
print('Net entity not in scope')
return
end
ก่อน
แล้วค่อย:
local entity =
NetworkGetEntityFromNetworkId(netId)
Native ตัวหลังคืน Local Entity Handle ของ NetID ที่กำหนด.
㊺ Entity มีบน Server แต่ไม่มีบน Client
นี่สามารถเป็น Behavior ปกติของ OneSync Scope
Client ไม่จำเป็นต้องสร้าง Entity ทุกตัวที่ Server รู้จัก และ Cfx.re ระบุว่า Network ID อาจไม่อยู่ใน Scope ของ Client.
อย่าแก้ด้วยการ Force ทุก Entity ให้ทุก Client เห็นโดยไม่จำเป็น
㊻ NetID ใช้ได้เมื่ออยู่ใกล้ แต่ใช้ไม่ได้เมื่อไกล
มีน้ำหนักสูงว่าเกี่ยวข้องกับ Scope/Culling
OneSync ลดการ Synchronize Entities ที่ไม่เกี่ยวข้องกับ Client เพื่อลด Network และ Processing Load.
ควรออกแบบ Resource ให้รองรับ Entity ที่เข้าและออก Scope
㊼ Resource ใช้ Entity Handle ข้าม Client แล้วพัง
ให้เปลี่ยน Architecture เป็น:
Client A Entity Handle
↓
Convert to Network ID
↓
Network Event
↓
Client B
↓
ตรวจ NetID in scope
↓
Convert to Local Entity Handle
เพราะ Entity Handles เป็น Local ต่อแต่ละ Client.
㊽ NetID เก่าชี้ Entity ผิด
จำว่า Network IDs สามารถถูก Reuse หลัง Entity เดิมหมด Lifetime.
จึงไม่ควรเก็บ:
netId = 143
ไว้ใน Database แล้วสมมติว่าเลข 143 จะเป็นรถเดิมหลัง Restart หรืออีกหลายชั่วโมงโดยไม่ตรวจ Lifecycle
㊾ วิธี Debug NetID แบบเร็ว
เพิ่ม Log:
print(('NetID=%s'):format(netId))
local exists =
NetworkDoesEntityExistWithNetworkId(netId)
print(('Exists=%s'):format(tostring(exists)))
if exists then
local entity =
NetworkGetEntityFromNetworkId(netId)
print(('Entity=%s'):format(entity))
end
จากนั้นเปรียบเทียบ:
Client A
Server
Client B
เพื่อดูว่า NetID อยู่ใน Scope ที่ใด
㊿ Checklist FiveM Network ID
ก่อนใช้ Production ตรวจว่า:
เข้าใจ Handle กับ NetID ต่างกัน
ไม่ส่ง Local Handle ข้าม Clients
ใช้
NetworkGetNetworkIdFromEntityตรวจ NetID ก่อน Resolve
ใช้
NetworkDoesEntityExistWithNetworkIdใช้
NetworkGetEntityFromNetworkIdเข้าใจ Scope
เข้าใจ Routing Bucket
เข้าใจ Entity Ownership
ไม่ใช้ NetID เป็น Database Primary Key
ไม่ Cache NetID หลัง Entity ถูกลบ
มี Timeout เมื่อรอ Entity
ไม่ Loop รอ Entity แบบไม่สิ้นสุด
Validate NetID จาก Client ฝั่ง Server
ตรวจ Permission ก่อน Entity Action
ใช้ State Bags กับ Runtime State เมื่อเหมาะสม
ใช้ Server-created Entity เมื่อเหมาะสม
Cleanup References เมื่อ Entity ถูกลบ
ทดสอบผู้เล่นหลายคน
ทดสอบ Entity เข้า/ออก Scope
ตาราง FiveM Entity IDs ที่ควรรู้
| ID/Reference | ใช้ทำอะไร | ถาวรหรือไม่ |
|---|---|---|
| Entity Handle | Local Entity Reference | ไม่ |
| Network ID | Network Entity Reference | ไม่ |
| Server ID | Player ใน Session | ไม่ |
| Player Identifier | Account Identity | ยาวกว่าระดับ Session |
| Database ID | Persistent Record | ขึ้นกับระบบ |
Entity Handle และ Network ID มีพฤติกรรมตาม Network IDs Documentation ของ Cfx.re.
ตัวอย่าง Client ส่ง Vehicle NetID ไป Server
client.lua
RegisterCommand('checkvehicle', function()
local ped = PlayerPedId()
local vehicle =
GetVehiclePedIsIn(ped, false)
if vehicle == 0 then
return
end
local netId =
NetworkGetNetworkIdFromEntity(vehicle)
TriggerServerEvent(
'example:checkVehicle',
netId
)
end, false)
server.lua
RegisterNetEvent(
'example:checkVehicle',
function(netId)
local src = source
local entity =
NetworkGetEntityFromNetworkId(netId)
if entity == 0 then
return
end
-- ตรวจ permission/state เพิ่มก่อนทำ Action
print(
('Player %s referenced entity %s')
:format(src, entity)
)
end
)
Server ควร Validate Client-triggered Event ก่อนทำ Action สำคัญเสมอ.
ตัวอย่าง Client รับ NetID จาก Server
RegisterNetEvent(
'example:receiveEntity',
function(netId)
if not NetworkDoesEntityExistWithNetworkId(netId) then
print('Entity not in scope')
return
end
local entity =
NetworkGetEntityFromNetworkId(netId)
print(
('Local entity handle: %s')
:format(entity)
)
end
)
Cfx.re แนะนำให้ตรวจ Network Entity Exists ก่อนใช้งานเมื่อ NetID อาจอยู่นอก Scope.
ตัวอย่าง Wait NetID แบบมี Timeout
local function waitForNetEntity(netId, timeoutMs)
local expires =
GetGameTimer() + timeoutMs
while not NetworkDoesEntityExistWithNetworkId(netId) do
if GetGameTimer() >= expires then
return nil
end
Wait(100)
end
return NetworkGetEntityFromNetworkId(netId)
end
วิธีนี้ปลอดภัยกว่า Loop ที่ไม่มี Timeout เพราะ Entity อาจอยู่นอก Scopeหรือถูกลบไปแล้ว
FiveM Entity Handle ส่งไป Server ได้ไหม
อย่าส่งเพื่อใช้เป็น Network Entity Reference
ควร:
local netId =
NetworkGetNetworkIdFromEntity(entity)
TriggerServerEvent(
'resource:event',
netId
)
เพราะ Handle เป็น Local ส่วน Network ID ถูกออกแบบสำหรับการอ้าง Entity ข้าม Machines.
FiveM NetID ส่งไป Client อื่นได้ไหม
ได้ในฐานะ Network Entity Reference
แต่ Client ปลายทางต้องตรวจว่า NetID นั้นอยู่ใน Scope และมี Local Entity ก่อนใช้งาน.
FiveM Network ID เปลี่ยนไหม
ตลอด Lifetime ของ Entity เดิม Network ID จะไม่เปลี่ยน แต่หลัง Entity หมด Lifetime หมายเลขดังกล่าวสามารถถูก Reuse ได้.
ดังนั้น NetID เหมาะกับ Runtime Networking ไม่ใช่ Persistent Identity
FiveM Entity Handle เปลี่ยนไหม
เปลี่ยนได้ และ Entity เดียวกันสามารถมี Handle คนละค่าบน Client แต่ละเครื่อง.
นี่คือเหตุผลว่าทำไมการส่ง Handle ระหว่าง Clients จึงไม่ใช่แนวทางที่ถูกต้อง
FiveM Network ID กับ OneSync ต่างกันอย่างไร
OneSync คือระบบ Synchronization
Network ID คือ Reference ของ Entity ที่ทำงานอยู่ใน Network Synchronization นั้น
OneSync ยังเกี่ยวข้องกับ Scope, Server-created Entities และ State Awareness เพิ่มเติม.
FiveM Network ID กับ State Bags ต่างกันอย่างไร
Network ID ระบุว่า:
Entity ตัวไหน
State Bag ระบุว่า:
Entity ตัวนั้นมี State อะไร
State Bags เป็น Key/Value Runtime State ที่ผูกกับ Entities ใน State Awareness Mode.
FiveM NetID หาไม่เจอเฉพาะบาง Player
มีโอกาสสูงว่า Client คนนั้นไม่มี Entity อยู่ใน Scope
ตรวจ:
Distance
Routing Bucket
Entity Lifecycle
Network Scope
ก่อนคิดว่า NetID เสีย
Cfx.re ระบุว่า Network ID ไม่จำเป็นต้องอยู่ใน Scope ของ Client ทุกเครื่อง.
FAQ FiveM Network ID
FiveM Network ID คืออะไร
เป็น 16-bit integer ที่ใช้แทน Networked Entity ในช่วง Lifetime หนึ่ง และใช้สำหรับอ้าง Entity ข้าม Clients/Server.
Network ID กับ Entity Handle ต่างกันอย่างไร
Entity Handle เป็น Local Reference ของแต่ละ Client ส่วน Network ID ใช้เป็น Network Reference ข้าม Machines.
แปลง Entity เป็น NetID อย่างไร
ใช้:
NetworkGetNetworkIdFromEntity(entity)
แปลง NetID เป็น Entity อย่างไร
ใช้:
NetworkGetEntityFromNetworkId(netId)
เพื่อรับ Local Entity Handle.
ทำไม NetID มีแต่หา Entity ไม่เจอ
เพราะ Network ID อาจอยู่นอก Client Scope ต้องตรวจด้วย:
NetworkDoesEntityExistWithNetworkId(netId)
ก่อนใช้งาน.
Network ID ใช้เป็น Database ID ได้ไหม
ไม่ควร เพราะ Network ID สามารถถูก Reuse หลัง Entity หมด Lifetime.
ส่ง Entity Handle ไป Client อื่นได้ไหม
ไม่ควรใช้เป็น Network Reference เพราะ Entity Handle เป็น Local ต่อแต่ละ Client ให้แปลงเป็น Network ID ก่อน.
NetID เปลี่ยนเมื่อ Entity Owner เปลี่ยนไหม
Network ID ไม่เปลี่ยนระหว่าง Lifetime ของ Entity แม้ Local Handle หรือ Ownership สามารถเปลี่ยนได้.
ประเด็นสำคัญ
FiveM Network ID หรือ NetID คือ Reference ที่ออกแบบมาเพื่อระบุ Networked Entity ข้าม Clients และ Server โดย Cfx.re ระบุว่า NetID เป็นค่า 16-bit ที่คงเดิมระหว่าง Lifetime ของ Entity แต่สามารถถูกนำกลับมาใช้ใหม่หลัง Entity นั้นหมดอายุแล้ว.
สูตรที่ Developer ควรจำให้แม่นคือ:
Entity Handle
= Local
Network ID
= Network
Database ID
= Persistent
เมื่อต้องส่ง Entity ข้าม Client/Server ให้ใช้ NetworkGetNetworkIdFromEntity() ก่อน และปลายทางต้องตรวจ NetworkDoesEntityExistWithNetworkId() ก่อนใช้ NetworkGetEntityFromNetworkId() เพราะ NetID ไม่จำเป็นต้องอยู่ใน Scope ของ Client ทุกเครื่อง.
เมื่อ NetID ถูกส่งมาจาก Client ฝั่ง Server ยังต้องตรวจ Entity, State และ Permission ก่อนทำ Action สำคัญ เพราะ Cfx.re แนะนำให้ Validate ข้อมูลจาก Client ที่ส่งผ่าน Network Events ไม่ใช่เชื่อ Arguments โดยอัตโนมัติ.
สำหรับผู้อ่าน comsiam ให้จำสูตร “Handle → NetID → Network → Handle” และ comsiam แนะนำให้ Resource ทุกตัวที่อ้าง Entity ข้ามเครื่องใช้ NetID พร้อมตรวจ Scope และ Entity Lifecycle เสมอ จะช่วยลดปัญหา Entity เป็น 0, รถหาย, Object คนละตัว และ Script ทำงานเฉพาะบาง Client
Comments
Post a Comment