FiveM Server-side Entity คืออะไร? สร้างและจัดการ Entity ฝั่ง Server ด้วย OneSync
FiveM Server-side Entity คือการที่ FXServer สามารถรับรู้ สร้าง ตรวจสอบ และจัดการ Entity เช่น Ped, Vehicle และ Object จาก Server Script ได้ผ่านระบบ OneSync/State Awareness โดยไม่จำเป็นต้องผลัก Logic ทุกอย่างไปให้ Client ทำเหมือนแนวทางเก่า
ตัวอย่าง Server สามารถหา Ped ของผู้เล่นได้
local ped =
GetPlayerPed(source)
อ่านตำแหน่ง
local coords =
GetEntityCoords(ped)
หรือสร้าง Vehicle จาก Server
local vehicle =
CreateVehicleServerSetter(
joaat('sultan'),
'automobile',
215.0,
-810.0,
30.0,
157.0
)
จากนั้น Server ยังสามารถกำหนด
Routing Bucket
State Bag
Orphan Mode
Mission State
Database Association
ให้ Entity ตาม Architecture ของ Resource
แต่สิ่งสำคัญคือ Server-side Entity ใน FiveM ไม่ได้หมายความว่า Server จำลอง Physics และเป็น Network Owner ของ Entity ทุกตัวตลอดเวลา
FiveM ยังใช้ระบบ Network Ownership ซึ่ง Client สามารถเป็นผู้ Simulation Entity และ Ownership สามารถเปลี่ยนได้
ดังนั้น Developer ต้องเข้าใจความแตกต่างระหว่าง
Server-created Entity
Server Entity Handle
Network ID
Network Owner
Server Authority
ให้ชัดเจน
① FiveM Server-side Entity คืออะไร
ใน OneSync State Awareness Server สามารถมี Entity Handle สำหรับ Networked Entity ได้
เอกสาร Cfx.re ระบุว่า Entity Handle ฝั่ง Serverใช้งานได้เมื่อ State Awareness ไม่ได้ถูก Disable
ดังนั้น Server สามารถทำงานกับ
Ped
Vehicle
Object
Entity
ผ่าน Server-side Natives ที่รองรับ
② เมื่อก่อนทำไม Entity Logic มักอยู่ Client
FiveM รุ่นเก่ามี Game Interaction จำนวนมากที่ต้องทำ Client-side
เช่น
Spawn Vehicle
หา Ped
อ่าน Coordinates
จัดการ Physics
แต่ OneSync เพิ่ม Server-side Synchronization State ทำให้ Server สามารถรับรู้ Entity State และใช้ Native ฝั่ง Serverได้มากขึ้น
นี่เปิดทางให้ Script ออกแบบแบบ Server-authoritative ได้ดีขึ้น
③ Server-side Entity ต้องใช้ OneSync ไหม
สำหรับ Server-side State Awareness ต้องใช้ OneSync
server.cfg
set onesync on
และ Resource ที่จำเป็นต้องใช้สามารถประกาศ
dependency '/onesync'
ใน fxmanifest.lua
เพื่อบอกว่า Resource ต้องการ State Awareness
④ Server-side Entity Handle คืออะไร
เป็น Handle ที่ Server Runtime ใช้อ้างถึง Entity
ตัวอย่าง
local ped =
GetPlayerPed(source)
ped คือ Server-side Ped Handle
สามารถใช้กับ Server Native ที่รองรับ เช่น
local coords =
GetEntityCoords(ped)
แต่ Handle ไม่ควรถูกมองเป็น Permanent ID
⑤ Server Entity Handle กับ Client Handle เหมือนกันไหม
ไม่ควรคาดหวังว่าเหมือนกัน
Entity เดียวกันอาจมี
Server Handle = X
Client A Handle = Y
Client B Handle = Z
หากต้องอ้าง Network Entity ข้าม Machines ควรใช้
Network ID
แทนการส่ง Local Handle ไปมา
⑥ Network ID ยังจำเป็นอยู่ไหม
จำเป็น
Entity Handle เหมาะกับ Runtime Context นั้น
แต่ Network ID ใช้บอกว่า
กำลังพูดถึง Network Entity ตัวไหน
ตัวอย่าง
local netId =
NetworkGetNetworkIdFromEntity(
vehicle
)
แล้วสามารถส่ง Net ID ไปยัง Client ที่เกี่ยวข้อง
⑦ Server หา Player Ped ได้อย่างไร
ใช้
local ped =
GetPlayerPed(
source
)
ตัวอย่าง Server Event
RegisterNetEvent(
'job:complete',
function()
local src =
source
local ped =
GetPlayerPed(src)
if ped == 0 then
return
end
end
)
source คือ Player Server ID
ส่วน ped คือ Entity
เป็นคนละ Identifier
⑧ Server อ่าน Coordinates ได้อย่างไร
หลังมี Ped
local coords =
GetEntityCoords(ped)
สามารถใช้ตรวจ
Mission
Shop
Garage
Job
Interaction
Security
ได้
เช่นตรวจ Player อยู่ใกล้จุดส่งงานหรือไม่
⑨ Server Position Validation สำคัญอย่างไร
สมมติ Client ส่ง
TriggerServerEvent(
'delivery:finish'
)
Server ไม่ควรเชื่อว่า Player อยู่จุด Delivery จริง
Server ตรวจเองได้
local ped =
GetPlayerPed(src)
if ped == 0 then
return
end
local coords =
GetEntityCoords(ped)
if #(coords - finishCoords)
> 10.0 then
return
end
นี่เป็น Use Case สำคัญของ Server-side Entity State
⑩ Client Coordinates ยังต้องส่งไหม
ในหลาย Security-sensitive Use Cases ไม่จำเป็น
ไม่ควรออกแบบ
TriggerServerEvent(
'job:finish',
GetEntityCoords(
PlayerPedId()
)
)
แล้ว Serverเชื่อ Coordinates จาก Client
เมื่อ Server สามารถหาตำแหน่ง Player จาก Server-side Entity State ได้เอง ก็ควรใช้ข้อมูลนั้นเป็น Validation Source
⑪ Server สร้าง Vehicle ได้ไหม
ได้
OneSync รองรับ Server-created Vehicles
ตัวอย่างที่ Cfx.re แนะนำ
local vehicle =
CreateVehicleServerSetter(
joaat('blista'),
'automobile',
2204.795,
-887.9213,
1461.224,
90.0
)
Entity จะถูก Register กับ Server
⑫ CreateVehicleServerSetter คืออะไร
เป็น Server Setter สำหรับสร้าง Vehicle จาก Server
รูปแบบหลักคือ
CreateVehicleServerSetter(
modelHash,
type,
x,
y,
z,
heading
)
ข้อดีสำคัญคือสามารถสร้าง Server Entity แม้ยังไม่มี Player อยู่ใกล้ใน OneSync Focus Range
⑬ Vehicle Type ต้องระบุอะไร
Parameter type บอกประเภท Vehicle เช่น
automobile
bike
boat
heli
plane
submarine
trailer
train
ตาม Native/Vehicle Type ที่รองรับ
ตัวอย่างรถทั่วไป
CreateVehicleServerSetter(
joaat('sultan'),
'automobile',
x,
y,
z,
heading
)
ต้องเลือก Type ให้ตรงกับ Vehicle ที่สร้าง
⑭ CreateVehicle กับ CreateVehicleServerSetter ต่างกันอย่างไร
นี่สำคัญมาก
Server-side CreateVehicle() บางรูปแบบทำงานเป็น RPC Native
Concept คือ
Server
↓
เรียก CreateVehicle
↓
RPC
↓
Client ที่เหมาะสม
↓
สร้าง Entity
ส่วน CreateVehicleServerSetter() เป็น Server Setter ที่ Register Entity กับ Server โดยตรง
⑮ RPC Entity Creation มีข้อจำกัดอะไร
Cfx.re ระบุว่า Server RPC Entity Creation ต้องมี Player อยู่ใกล้ภายใน OneSync Focus Distance
และสามารถล้มเหลวได้ เช่น
Client ที่ถูกเลือก Disconnect
ไม่มี Player ใกล้
RPC ไม่สำเร็จ
ดังนั้นผลลัพธ์ต้องถูกตรวจเสมอ
⑯ ตัวอย่างตรวจ RPC Creation
Concept
local vehicle =
CreateVehicle(
joaat('adder'),
x,
y,
z,
heading,
true,
true
)
if vehicle == 0 then
print(
'Vehicle creation failed'
)
return
end
หลังจากนั้นอาจต้องรอ Entity Existence พร้อม Timeout
⑰ อย่า Wait Entity แบบไม่มี Timeout
ไม่ควร
while not DoesEntityExist(
vehicle
) do
Wait(50)
end
เพราะถ้า Creation Fail Thread จะรอไม่จบ
ควรใช้
local timeout =
GetGameTimer() + 10000
while not DoesEntityExist(
vehicle
)
and GetGameTimer() <
timeout do
Wait(50)
end
แล้วตรวจอีกครั้ง
⑱ Server Setter รับประกันอะไร
เอกสาร Migration ปัจจุบันระบุ Server Setter เช่น
CREATE_VEHICLE_SERVER_SETTER
CREATE_PED
CREATE_OBJECT_NO_OFFSET
สามารถ Register Entity กับ Server ได้ทันที
แม้ยังไม่มี Player อยู่ใกล้
แต่ Entity ที่สร้างในสถานการณ์นี้อาจเริ่มเป็น
Orphaned Entity
⑲ Orphaned Entity คืออะไร
คือ Server-created Entity ที่ยังไม่มี Client เหมาะสมอยู่ใน Scope เพื่อ Simulation
Concept
Server
↓
Create Entity
↓
ไม่มี Client อยู่ใกล้
↓
Entity registered
↓
Owner = -1
↓
Orphaned
เมื่อ Player เข้า Scope จึงสามารถมี Client Owner ได้
⑳ วิธีตรวจ Entity Owner ฝั่ง Server
ใช้
local owner =
NetworkGetEntityOwner(
entity
)
สำหรับ Orphaned Entity เอกสารปัจจุบันระบุว่าอาจได้
-1
เพราะยังไม่มี Client Owner
㉑ Owner -1 หมายถึง Entity ไม่มีจริงไหม
ไม่
นี่เป็นจุดสำคัญ
Server Setter สามารถ Register Entity กับ Serverได้แล้ว
แต่ยังไม่มี Client Simulation
ดังนั้น
owner == -1
ไม่จำเป็นต้องหมายถึง Entity Creation Failed
ต้องแยก
Server Entity Registration
ออกจาก
Client Simulation Ownership
㉒ Server Getter ใช้กับ Orphaned Entity ได้ไหม
เอกสาร Cfx.re ระบุว่า Server-side Getter บางตัวสามารถใช้กับ Orphaned Entity ได้
เช่นอ่าน Server State
แต่ RPC Native ที่ต้องส่งไป Client Owner อาจยังใช้ไม่ได้
เพราะไม่มี Owner
㉓ ตัวอย่าง RPC Native ที่อาจใช้ไม่ได้ตอน Orphaned
สมมติ Server สร้างรถในพื้นที่ไม่มี Player
จากนั้นเรียก RPC Setter ที่ต้อง Execute ฝั่ง Client
Server
↓
SetVehicleColours
↓
ต้องมี Client Owner
↓
ไม่มี
↓
อาจไม่ทำงาน
นี่เป็นสาเหตุของ Bug ที่ Developer พบได้บ่อย
㉔ วิธี Initialize Entity ที่ยังไม่มี Owner
Cfx.re แนะนำ Pattern ที่น่าสนใจคือ
Server Setter
↓
Create Entity
↓
Set State Bag
↓
Player เข้า Scope
↓
Client ได้ Ownership
↓
State Bag Handler
↓
Owner ทำ Local Initialization
ช่วยหลีกเลี่ยงการยิง RPC Native ก่อน Entity มี Owner
㉕ ตัวอย่าง Initialization State
Server
Entity(vehicle).state:set(
'vehicle:needsInit',
true,
true
)
Client ใช้
AddStateBagChangeHandler(
'vehicle:needsInit',
nil,
function(
bagName,
key,
value
)
if not value then
return
end
-- resolve entity
-- check owner
-- initialize
end
)
นี่เป็น Pattern ที่เหมาะกับ Ownership Migration
㉖ Server สร้าง Ped ได้ไหม
ได้
OneSync Documentation แสดงการสร้าง Ped จาก Server
local ped =
CreatePed(
4,
joaat('a_m_y_acult_01'),
x,
y,
z,
heading,
true,
true
)
จากนั้นสามารถใช้ Server-side Entity Lifecycle APIs ต่อ
㉗ Server สร้าง Object ได้ไหม
ได้ตาม Server-side Native ที่รองรับ เช่น Server Setter สำหรับ Object
Use Cases เช่น
Mission Prop
Crate
Barrier
World Object
Interactive Object
จากนั้นควรจัด
Routing Bucket
State
Persistence
Cleanup
ให้ Entity ด้วย
㉘ Server-created Entity ดีกว่า Client-created เสมอไหม
ไม่เสมอ
Local Visual Entity เช่น
Preview Object
Temporary UI Prop
Client-only Effect
อาจเหมาะให้ Client สร้าง
แต่ Entity ที่มีผลกับ Multiplayer Gameplay เช่น
Mission Vehicle
Reward Vehicle
Mission Ped
Shared Object
มักได้ประโยชน์จาก Server-controlled Creation
㉙ Server-created Entity ช่วย Security อย่างไร
แทนให้ Clientทำ
ฉัน Spawn Vehicle แล้ว
เชื่อฉัน
เปลี่ยนเป็น
Client:
ขอ Vehicle
Server:
มีสิทธิ์ไหม?
Mission ถูกไหม?
Model ถูกไหม?
Cooldown ผ่านไหม?
↓
Server Create
ช่วยลด Client Authority
แต่ไม่ได้ทำให้ Entity Security สมบูรณ์โดยอัตโนมัติ
㉚ อย่าให้ Client ส่ง Model อะไรก็ได้
ตัวอย่าง Event ที่เสี่ยง
RegisterNetEvent(
'vehicle:spawn',
function(model)
local vehicle =
CreateVehicleServerSetter(
joaat(model),
'automobile',
...
)
end
)
ถ้าไม่มี Allowlist Client อาจพยายาม Spawn Model ที่ไม่ควรได้รับ
ควรใช้ Server-side Allowlist
㉛ ตัวอย่าง Model Allowlist
local AllowedVehicles = {
sultan = 'automobile',
blista = 'automobile'
}
Server
local vehicleType =
AllowedVehicles[model]
if not vehicleType then
return
end
แล้วจึง Spawn
Client ขอ Action
Server ตัดสินว่ารุ่นไหนอนุญาต
㉜ Entity Lockdown ช่วยได้ไหม
ช่วย
Routing Bucket สามารถตั้ง
SetRoutingBucketEntityLockdownMode(
bucket,
'strict'
)
เพื่อไม่ให้ Client สร้าง Entity ใน Bucket นั้น
จากนั้นใช้ Pattern
Client Request
↓
Server Validate
↓
Server Create
ช่วยลด Client-created Entity Abuse
㉝ strict เหมาะกับ Server ทุกแบบไหม
ไม่
Resource เก่าบางตัวพึ่ง Client Spawn
เช่น
Vehicle
Ped
Object
ถ้าเปิด strict อาจทำให้ Resource พัง
ต้อง Audit Resource ก่อนใช้ Entity Lockdown ที่เข้มงวด
㉞ Server Entity กับ Routing Bucket
Server-created Entity สามารถถูกย้ายไป Bucket
SetEntityRoutingBucket(
vehicle,
bucket
)
ตัวอย่าง Mission
Player
Bucket 100
Vehicle
Bucket 100
NPC
Bucket 100
Object
Bucket 100
ทุก Entity อยู่ Instance เดียวกัน
㉟ ตรวจ Entity Bucket
ใช้
local bucket =
GetEntityRoutingBucket(
entity
)
มีประโยชน์กับ Debug
เช่น Player ไม่เห็น Vehicle เพราะ
Player Bucket = 100
Vehicle Bucket = 0
㊱ Server Entity กับ State Bag
Server สามารถผูก Custom State กับ Entity
Entity(vehicle).state:set(
'fuel',
100,
true
)
หรือ
Entity(vehicle).state:set(
'mission:id',
missionId,
true
)
Relevant Clients สามารถอ่าน State ตาม OneSync Replication Policy
㊲ ทำไม State Bag เหมาะกับ Server Entity
เพราะ Entity Ownership อาจเปลี่ยน
แต่ State ถูกผูกกับ Network Entity
ตัวอย่าง
Vehicle
↓
fuel = 80
mission:id = 15
↓
Owner A
↓
Ownership Migration
↓
Owner B
Custom State ไม่ต้องผูกกับ Local Variable ของ Owner A คนเดียว
㊳ Server Entity กับ Network ID
Serverสามารถหา Network ID
local netId =
NetworkGetNetworkIdFromEntity(
vehicle
)
แล้วส่งให้ Client
TriggerClientEvent(
'mission:setVehicle',
src,
netId
)
Client Resolve เมื่อ Entity อยู่ใน Scope
㊴ อย่าส่ง Server Entity Handle ไปใช้เป็น Client Handle
ถึงแม้บางเลขอาจบังเอิญดูใช้งานได้ในบาง Context ก็ไม่ควรออกแบบแบบนั้น
ควร
Server Entity Handle
↓
Network ID
↓
Client
↓
Local Entity Handle
เพราะ Handle เป็น Context-specific Reference
㊵ Client Resolve Net ID อย่างไร
if not NetworkDoesEntityExistWithNetworkId(
netId
) then
return
end
local vehicle =
NetToVeh(netId)
if not DoesEntityExist(vehicle) then
return
end
ถ้า Entity ยังไม่อยู่ Scope อาจต้องรอพร้อม Timeout
㊶ Server Delete Entity ได้ไหม
Server สามารถใช้ Server-side Entity APIs ที่รองรับ เช่น
if DoesEntityExist(entity) then
DeleteEntity(entity)
end
เหมาะกับ Server-owned Mission Lifecycle
แต่ต้องระวังว่า Entity Handle ยัง Valid หรือไม่ก่อน Delete
㊷ Entity Cleanup สำคัญแค่ไหน
สำคัญมาก
Server-created Entities ที่ไม่ Cleanup สามารถสะสมเป็น
Vehicles
Peds
Objects
จนเพิ่ม
Network Load
Memory
Entity Density
Client Streaming Cost
ทุกระบบ Spawn ควรมี Delete Strategy
㊸ Mission Entity Lifecycle ควรเป็นอย่างไร
Mission Start
↓
Server Create Entities
↓
Store Entity References
↓
Mission Active
↓
Mission Complete / Cancel
↓
Delete Entities
↓
Clear State
อย่าสร้าง Entity แล้วลืม
㊹ เก็บ Server Entity Handle ใน Table ได้ไหม
ได้ใน Runtime
local Missions = {}
Missions[id] = {
vehicle = vehicle
}
ตอนใช้ควรตรวจ
local entity =
Missions[id].vehicle
if not DoesEntityExist(entity) then
return
end
และ Clear เมื่อ Entity Lifecycle จบ
㊺ เก็บ Entity Handle ใน Database ได้ไหม
ไม่ควร
Entity Handle เป็น Runtime Reference
Database ควรเก็บ Persistent Data เช่น
vehicle_id
plate
model
coords
owner
properties
แล้วสร้าง Runtime Entity ใหม่เมื่อต้องการ
㊻ เก็บ Network ID ใน Database ได้ไหม
ก็ไม่ควรใช้เป็น Permanent Identity
Network ID สามารถถูก Reuse หลัง Entity เดิมหมด Lifetime
จึงเหมาะกับ
Runtime cross-machine reference
ไม่ใช่
Permanent database key
㊼ SetEntityOrphanMode คืออะไร
ใช้กำหนด Orphan Mode ของ Server-created Entity
ตัวอย่าง
SetEntityOrphanMode(
vehicle,
2
)
Mode 2 คือ KeepEntity ตาม OneSync Documentation
ช่วยให้ Server ไม่ Delete Entity เพียงเพราะไม่มี Client Owner
㊽ KeepEntity คือ Persistence ไหม
เป็น Runtime Persistence ในความหมายหนึ่ง
แต่ไม่ใช่ Database Persistence
KeepEntity
≠
อยู่หลัง FXServer Restart
ถ้าต้องการ Persistence ข้าม Restart ต้องใช้ Persistent Storage แล้ว Respawn Entity
㊾ Client ยัง Delete KeepEntity ได้ไหม
เอกสาร OneSync ระบุว่า KeepEntity รับประกันว่า Server จะไม่ลบ Entity จากเหตุ Orphan Lifecycle
แต่ Client ยังสามารถ Request การ Delete Entity ได้ใน Networking Model ที่อนุญาต
ดังนั้นหากต้องการ Security เพิ่มต้องพิจารณา
Entity Lockdown
Control Filtering
Server Validation
Resource Design
ร่วมด้วย
㊿ Network Ownership ยังมีผลกับ Server Entity ไหม
มี
Server-created ไม่ได้หมายความว่า Serverเป็น Network Owner ตลอดเวลา
เมื่อ Client เข้ามาใน Scope Client สามารถรับ Network Simulation Ownership
และ Ownership สามารถ Migration ได้
นี่เป็น Behavior หลักของ OneSync
51 Server-side Entity Authority คืออะไร
ควรแยกสองคำ
Network Ownership
กับ
Business Authority
แม้ Client A เป็น Network Owner ของ Vehicle
Server ยังสามารถเป็น Authority ว่า
ใครเป็นเจ้าของรถ
รถขายได้ไหม
รถเป็น Mission Vehicle ไหม
Reward เท่าไร
ได้
นี่คือ Architecture ที่เหมาะกับ FiveM
52 Server Entity กับ ESX
ESX สามารถใช้ Server Entity APIs ร่วมกับ Framework Data ได้
ตัวอย่าง
ESX Player
↓
Database Vehicle Ownership
↓
Server Entity
↓
Network ID
↓
State Bag
Framework จัด Business State
OneSync จัด Multiplayer Entity State
53 Server Entity กับ QBCore
หลักเดียวกัน
QBCore Player/Vehicle Data สามารถใช้ร่วมกับ
Server-created Vehicle
Routing Bucket
State Bags
Network ID
ได้
อย่าคิดว่า Framework API ต้องแทน FiveM Core Entity APIs ทุกอย่าง
54 Server Entity กับ Qbox
Qbox ก็ใช้แนวคิดเดียวกัน
Developer ที่เข้าใจ Core Entity Architecture จะสามารถสร้าง Bridge Layer
Framework
↓
Business State
OneSync
↓
Entity State
ได้ง่ายกว่า
55 Server Entity Performance ต้องระวังอะไร
อย่าทำ Server Thread แบบ
while true do
Wait(0)
for _, entity in pairs(
thousandsOfEntities
) do
GetEntityCoords(entity)
end
end
Server-side Entity API ก็มี Cost
ควรออกแบบ
Event-driven
Reasonable intervals
Spatial logic
Cached State
Cleanup
ตาม Requirement
56 Server-created Entity จำนวนมากได้ไม่จำกัดไหม
ไม่
แม้ OneSync มี Server-side Streaming และ Object ID Space ขนาดใหญ่ แต่ Game Clients ยังมี Streaming/Entity Limits
Cfx.re เตือนว่า Entities จำนวนมากเกินไปใน Range เดียวสามารถทำให้ Clients มีปัญหาหรือ Timeout ได้
ดังนั้น
Server-created
≠
Unlimited entities
57 RPC Native ต้องระวังอะไร
จำสามข้อ
① RPC Native อาจต้องมี Client Owner
② RPC Calls สามารถล้มเหลว
③ Ownership เปลี่ยนได้
ดังนั้น Critical Initialization ไม่ควรพึ่ง RPC Call หนึ่งครั้งแล้วไม่ตรวจผล
Server Setter + State Bag + Owner Handler อาจ Robust กว่าในหลาย Use Cases
58 วิธี Debug Server-side Entity
เริ่มจาก Print
print(
'entity:',
entity
)
print(
'exists:',
DoesEntityExist(entity)
)
print(
'owner:',
NetworkGetEntityOwner(entity)
)
print(
'bucket:',
GetEntityRoutingBucket(entity)
)
หา Network ID
local netId =
NetworkGetNetworkIdFromEntity(
entity
)
print(
'netId:',
netId
)
แล้วตรวจ State Bags และ Client Scope ต่อ
59 Checklist ก่อนใช้ Server-side Entity
ตรวจอย่างน้อย
① OneSync เปิดหรือยัง?
② Resource ต้องประกาศ /onesync หรือไม่?
③ Entity ควรสร้าง Server หรือ Client?
④ ถ้า Server สร้าง ใช้ Server Setter หรือ RPC?
⑤ RPC Creation สามารถ Fail หรือไม่?
⑥ ตรวจ entity == 0 หรือยัง?
⑦ มี Timeout ตอน Wait Entity หรือไม่?
⑧ Entity เป็น Orphaned ได้ไหม?
⑨ Owner == -1 ถูก Handle หรือไม่?
⑩ Initialization ต้องใช้ Client Owner หรือไม่?
⑪ ใช้ State Bag ช่วยได้ไหม?
⑫ Entity อยู่ Routing Bucket ไหน?
⑬ Entity ต้อง KeepEntity หรือไม่?
⑭ Entity มี Network ID หรือไม่?
⑮ Client ได้รับ Net ID หรือ Handle?
⑯ Security ตรวจ Model/Permission หรือไม่?
⑰ Client สามารถ Spawn Entity เองได้หรือไม่?
⑱ ต้องใช้ Entity Lockdown หรือไม่?
⑲ Entity Cleanup เมื่อไร?
⑳ Entity Handle ถูกเก็บใน Database หรือไม่?
㉑ Network ID ถูกใช้เป็น Persistent ID หรือไม่?
㉒ Entity Density สูงเกินไปหรือไม่?
㉓ Server Loop Entity หนักเกินไปหรือไม่?
⑥⓪ ตัวอย่าง Server-side Mission Vehicle แบบสมบูรณ์
server.lua
local MissionVehicles = {}
local AllowedVehicles = {
sultan = 'automobile',
blista = 'automobile'
}
RegisterNetEvent(
'mission:createVehicle',
function(model)
local src =
source
if type(model) ~= 'string' then
return
end
local vehicleType =
AllowedVehicles[model]
if not vehicleType then
return
end
if MissionVehicles[src] then
local oldVehicle =
MissionVehicles[src]
if DoesEntityExist(
oldVehicle
) then
return
end
MissionVehicles[src] =
nil
end
local ped =
GetPlayerPed(src)
if ped == 0 then
return
end
local coords =
GetEntityCoords(ped)
local heading =
GetEntityHeading(ped)
local bucket =
GetPlayerRoutingBucket(src)
local vehicle =
CreateVehicleServerSetter(
joaat(model),
vehicleType,
coords.x + 5.0,
coords.y,
coords.z,
heading
)
if vehicle == 0 then
return
end
SetEntityRoutingBucket(
vehicle,
bucket
)
SetEntityOrphanMode(
vehicle,
2
)
Entity(vehicle).state:set(
'mission:vehicle',
true,
true
)
Entity(vehicle).state:set(
'mission:owner',
src,
true
)
MissionVehicles[src] =
vehicle
local netId =
NetworkGetNetworkIdFromEntity(
vehicle
)
TriggerClientEvent(
'mission:vehicleCreated',
src,
netId
)
end
)
client.lua
RegisterNetEvent(
'mission:vehicleCreated',
function(netId)
if type(netId) ~= 'number' then
return
end
local timeout =
GetGameTimer() + 5000
while not
NetworkDoesEntityExistWithNetworkId(
netId
) do
if GetGameTimer() >
timeout then
return
end
Wait(0)
end
local vehicle =
NetToVeh(netId)
if not DoesEntityExist(
vehicle
) then
return
end
print(
'Mission vehicle ready:',
vehicle
)
end
)
Cleanup
local function removeMissionVehicle(
src
)
local vehicle =
MissionVehicles[src]
if not vehicle then
return
end
MissionVehicles[src] =
nil
if DoesEntityExist(
vehicle
) then
DeleteEntity(
vehicle
)
end
end
AddEventHandler(
'playerDropped',
function()
removeMissionVehicle(
source
)
end
)
Flow ของระบบคือ
Client
↓
ขอ Mission Vehicle
↓
Server Validate Model
↓
Server หา Player Position
↓
Server หา Routing Bucket
↓
CreateVehicleServerSetter
↓
Set Bucket
↓
KeepEntity
↓
Set State Bags
↓
Network ID
↓
Client
↓
Resolve Local Vehicle
นี่เป็นพื้นฐาน Server-side Entity Architecture ที่สามารถต่อยอดได้อีกมาก
คำถามที่พบบ่อยเกี่ยวกับ FiveM Server-side Entity
FiveM Server-side Entity คืออะไร
คือการที่ Server สามารถรับรู้และจัดการ Entity Handles/State เช่น Ped, Vehicle และ Object ผ่าน OneSync State Awareness
ต้องเปิด OneSync ไหม
ต้องใช้ State Awareness สำหรับ Server-side Entity Features ที่เกี่ยวข้อง
Server หา Player Ped ได้ไหม
ได้ เช่น
GetPlayerPed(source)
Server หา Coordinates ได้ไหม
ได้
GetEntityCoords(
ped
)
ตาม Server-side API ที่รองรับ
Server สร้าง Vehicle ได้ไหม
ได้
วิธีที่แนะนำคืออะไร
สำหรับ Server Setter ใช้ API เช่น
CreateVehicleServerSetter(...)
ใน Use Case ที่เหมาะสม
Server CreateVehicle() กับ Server Setter เหมือนกันไหม
ไม่ Server CreateVehicle() สามารถเป็น RPC Creation ซึ่งต้องพึ่ง Client ใกล้และสามารถล้มเหลวได้ ส่วน Server Setter Register Entity กับ Serverโดยตรง
RPC Native คืออะไร
คือ Native ที่ Server เรียกแต่ Operation ถูกส่งไปทำบน Client ซึ่งโดยทั่วไปเป็น Client Owner
RPC Native สำเร็จเสมอไหม
ไม่ Cfx.re ระบุว่าสามารถ Fail ได้
Orphaned Entity คืออะไร
Server-created Entity ที่ยังไม่มี Client อยู่ใน Scope รับ Simulation Ownership
NetworkGetEntityOwner คืน -1 หมายถึงอะไร
สำหรับ Orphaned Entity หมายถึงยังไม่มี Client Owner
Entity ยังมีอยู่ถ้า Owner -1 ไหม
Server Setter สามารถ Register Entity กับ Serverได้แม้ยังไม่มี Client Simulation
SetEntityOrphanMode 2 คืออะไร
คือ KeepEntity Mode ซึ่งช่วยไม่ให้ Server Cleanup Entity เพราะไม่มี Client Owner
KeepEntity อยู่หลัง Restart ไหม
ไม่ ต้องใช้ Database/Persistent Storage หากต้องการข้าม Restart
Server-created Entity มี Server เป็น Owner ตลอดไหม
ไม่ Network Simulation Ownership ยังสามารถไปอยู่กับ Client และ Migration ได้
Server-created Entity ปลอดภัยจาก Cheat ไหม
ช่วยลด Client Creation Authority แต่ยังต้องมี Event Validation, Entity Lockdown และ Security Logic ตามระบบ
Client ส่ง Model ให้ Server ได้ไหม
ส่งเป็น Request ได้ แต่ Server ควรตรวจ Allowlist ก่อนสร้าง
Server ส่ง Entity ไป Client อย่างไร
ควรส่ง Network ID มากกว่า Server Entity Handle
Network ID เก็บ Database ได้ไหม
ไม่ควรเป็น Permanent Identity
Entity Handle เก็บ Database ได้ไหม
ไม่ควร
Server Entity อยู่ Routing Bucket ได้ไหม
ได้ด้วย SetEntityRoutingBucket()
Server Entity มี State Bag ได้ไหม
ได้ผ่าน Entity(entity).state
Server Delete Entity ได้ไหม
ได้ผ่าน Server-side Native ที่รองรับ เช่น DeleteEntity() ตาม Context
Entity จำนวนมากไม่จำกัดใช่ไหม
ไม่ Client/Game Streaming Limits ยังมีอยู่ และ Entity Density สูงเกินไปสามารถสร้างปัญหาได้
สรุป FiveM Server-side Entity คืออะไร
FiveM Server-side Entity คือความสามารถของ FXServer ภายใต้ OneSync ที่ทำให้ Server รับรู้ สร้าง ตรวจสอบ และจัดการ Networked Ped, Vehicle และ Object ได้มากขึ้น
ตัวอย่าง Player State
local ped =
GetPlayerPed(source)
local coords =
GetEntityCoords(ped)
ช่วยให้ Server ตรวจ Gameplay State เองได้ เช่น
Player อยู่จุด Mission จริงไหม?
Player อยู่ใกล้ Shop ไหม?
Player อยู่ใกล้ Vehicle หรือไม่?
ส่วน Entity Creation สามารถใช้ Server Setter เช่น
local vehicle =
CreateVehicleServerSetter(
joaat('sultan'),
'automobile',
x,
y,
z,
heading
)
แล้วจัดการต่อด้วย
Routing Bucket
Orphan Mode
State Bag
Network ID
Lifecycle
Cleanup
แต่ต้องแยกให้ชัดว่า
Server-created Entity
≠
Server เป็น Network Owner ตลอดเวลา
Entity สามารถเริ่มเป็น Orphaned เมื่อยังไม่มี Client ใน Scope และ NetworkGetEntityOwner() สามารถคืน -1
เมื่อ Client เข้ามา Ownership สามารถถูกมอบให้ Client และภายหลัง Migration ได้อีก
อีกเรื่องสำคัญคือ Server-side RPC Natives ไม่ได้มี Guarantee ว่าจะทำงานทุกครั้ง เพราะ Operation อาจต้องถูก Execute บน Client Owner
ดังนั้น Resource ขั้นสูงควรแยกระหว่าง
Server Setter
RPC Native
Server Getter
Client-owner Initialization
ให้ถูกต้อง
สำหรับผู้ที่เรียน FiveM Developer กับ comsiam จุดแข็งที่สุดของ Server-side Entity ไม่ใช่เพียง “Spawn รถจาก Server ได้” แต่คือการย้าย Authority ของ Gameplay สำคัญกลับมาอยู่บน Server ให้มากขึ้น เช่น Serverเป็นคนตรวจ Player, เลือก Model, สร้าง Entity, กำหนด Instance และควบคุม Lifecycle
หลักสำคัญจาก comsiam คือ Client ควรขอให้ Server ทำสิ่งหนึ่ง ส่วน Server ตรวจว่าทำได้หรือไม่ แล้วจึงสร้างหรือเปลี่ยน Entity ตาม State ที่ Serverเชื่อถือได้
หัวข้อถัดไปคือ FiveM Entity Lockdown คืออะไร ป้องกัน Client Spawn Entity อย่างไร ซึ่งจะต่อจาก Server-created Entity โดยตรง และเจาะการใช้ strict, relaxed, inactive รวมถึง Routing Bucket เพื่อสร้างระบบที่ Client ไม่สามารถ Spawn Entity ได้ตามใจ
Comments
Post a Comment