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

Popular posts from this blog

FiveM ยังน่าเล่นไหม? Enhanced เปลี่ยน FiveM แค่ไหน

FiveM คืออะไร เล่นอย่างไร สำหรับมือใหม่ เริ่มต้นตั้งแต่ศูนย์

วิธีตั้ง Admin Permission ด้วย add_ace และ add_principal FiveM แบบละเอียด