FiveM SetEntityOrphanMode คืออะไร? KeepEntity ทำงานอย่างไร และใช้กับ Server-created Entity เมื่อไหร่
FiveM SetEntityOrphanMode คือ Native ฝั่ง Server ที่ใช้กำหนดพฤติกรรมของ Entity เมื่อตกอยู่ในสถานะที่ไม่มี Client Owner เหมาะสม โดยเฉพาะกับ Server-created Entities เช่น Vehicle, Ped และ Object ภายใต้ OneSync ซึ่ง Cfx.re แนะนำ SetEntityOrphanMode(entity, 2) หรือโหมด KeepEntity เมื่อต้องการป้องกันไม่ให้ Server ลบ Entity นั้นจากกระบวนการ Cleanup ของ Server เอง.
สิ่งที่ต้องเข้าใจตั้งแต่แรกคือ KeepEntity ไม่ได้หมายความว่า Entity จะไม่มีวันหาย และไม่ได้หมายถึงการบันทึก Entity หลัง Server Restart เพราะ Cfx.re ระบุว่าแม้ Server จะไม่ลบ Entity จาก Orphan Cleanup แต่ Client ยังสามารถร้องขอการลบ Entity ได้.
① SetEntityOrphanMode คืออะไร
รูปแบบพื้นฐานที่พบใน OneSync Documentation คือ:
SetEntityOrphanMode(entity, 2)
โดย Cfx.re ใช้ร่วมกับ Server-created Vehicle และ Ped เพื่อให้ Entity มี Persistence ในระดับ Server Runtime มากขึ้น.
ตัวอย่าง:
local vehicle = CreateVehicleServerSetter(
GetHashKey('blista'),
'automobile',
2204.795,
-887.9213,
1461.224,
90.0
)
SetEntityOrphanMode(vehicle, 2)
② Orphaned Entity คืออะไร
Server Setter Native เช่น:
CreateVehicleServerSetter
CreatePed
CreateObjectNoOffset
สามารถ Register Entity กับ Server ได้ทันที แต่ Cfx.re ระบุว่า Entity ที่เพิ่งสร้างอาจเริ่มต้นในสถานะ orphaned จนกว่าจะมี Client ที่เหมาะสมเข้ามาอยู่ใน Scope.
โครงสร้างคือ:
Server สร้าง Entity
↓
Entity ถูก Register
↓
ยังไม่มี Client Owner
↓
Orphaned
↓
Client ที่เหมาะสมเข้า Scope
↓
Entity ถูก Simulate
③ Orphaned ไม่ได้หมายความว่า Entity Creation ล้มเหลว
นี่เป็นจุดที่ Developer มักเข้าใจผิด
หากใช้ Server Setter แล้วได้ Entity Handle สำเร็จ แต่:
NetworkGetEntityOwner(entity)
คืน:
-1
Cfx.re ระบุว่านี่เป็น Behavior ปกติเมื่อ Entity ยังอยู่ในสถานะ Orphaned.
④ NetworkGetEntityOwner ได้ -1 คืออะไร
หมายความว่า ณ เวลานั้น Server ยังไม่มี Client ที่เป็น Suitable Owner สำหรับ Entity
ไม่ได้แปลทันทีว่า:
Entity เสีย
NetID เสีย
OneSync พัง
ควรตรวจ Scope และ Routing Bucket ก่อน.
⑤ Orphan Mode 2 คืออะไร
Cfx.re เรียก Flag ที่ใช้กับ Mode 2 ว่า KeepEntity
จุดประสงค์คือรับประกันว่า Server จะไม่ Remove Entity ด้วย Server-side Orphan Cleanup ตาม Behavior ที่ Documentation อธิบาย.
จำง่ายๆ:
SetEntityOrphanMode(entity, 2)
=
KeepEntity
⑥ KeepEntity ทำให้ Entity อยู่ตลอดไปไหม
ไม่
Cfx.re ระบุชัดว่า แม้ KeepEntity จะป้องกัน Server จากการลบ Entity ตาม Policy นี้ แต่ Client ยังสามารถ Request การลบ Entity ได้.
ดังนั้นคำว่า Persistent ในบริบทนี้หมายถึง:
Persistent ระหว่าง Runtime
ไม่ใช่:
Immutable Entity
⑦ KeepEntity อยู่หลัง Server Restart ไหม
ไม่
FXServer Restart ทำให้ Runtime Entity เดิมหายไป
หากต้องการ Vehicle หรือ Object กลับมาหลัง Restart ต้องเก็บ Persistent Data แยก เช่น:
Database ID
Model
Coordinates
Heading
State สำคัญ
แล้วสร้าง Entity ใหม่เมื่อ Server เริ่ม
SetEntityOrphanMode จึงไม่ใช่ Database หรือ Save System
⑧ KeepEntity กับ Persistent Vehicle ต่างกันอย่างไร
KeepEntity
ช่วยรักษา Runtime Entity
Persistent Vehicle System
เก็บข้อมูลรถถาวร
↓
Server Restart
↓
โหลดข้อมูล
↓
สร้าง Entity ใหม่
จึงเป็นคนละ Layer
⑨ Server-created Vehicle ควรใช้ SetEntityOrphanMode ไหม
ถ้ารถนั้นต้องอยู่ต่อแม้ไม่มี Client Owner ชั่วคราว การใช้:
SetEntityOrphanMode(vehicle, 2)
เป็น Pattern ที่ OneSync Documentation แนะนำสำหรับ Server-created Entity.
⑩ Server-created Ped ใช้ได้ไหม
ได้
Official Example ใช้:
local ped = CreatePed(
4,
GetHashKey('a_m_y_acult_01'),
2204.795,
-887.9213,
1461.224,
90.0,
true,
true
)
SetEntityOrphanMode(ped, 2)
เพื่อให้ Server-created Ped มี KeepEntity Behavior.
⑪ Server-created Object ใช้ได้ไหม
Server Setter Entity Creation ของ FiveM รองรับ Object ผ่าน Server-side Entity Creation APIs เช่น CREATE_OBJECT_NO_OFFSET และ Entity ที่สร้างสามารถจัด Lifecycle ด้วย Server-side Entity Management ตาม Use Case.
หาก Object ต้องคงอยู่ใน Runtime แม้ไม่มี Owner ชั่วคราว ก็ควรพิจารณา Orphan Policy เช่นเดียวกัน
⑫ CreateVehicleServerSetter กับ Orphan Mode ทำงานอย่างไร
Flow ที่แนะนำ:
CreateVehicleServerSetter
↓
ตรวจ Entity
↓
SetEntityOrphanMode(entity, 2)
↓
Set Routing Bucket ถ้าจำเป็น
↓
Set State Bags
↓
OneSync จัด Scope/Owner
Cfx.re แสดง CreateVehicleServerSetter + SetEntityOrphanMode(..., 2) เป็น Pattern โดยตรงใน Best Practices ของ OneSync.
⑬ ทำไม Server Setter Entity ถึงเริ่ม Orphaned
เพราะ Server Setter Register Entity กับ Server ได้ทันทีโดยไม่ต้องมี Player ใกล้ๆ แต่ Client Simulation ยังต้องมี Suitable Client อยู่ใน Scope.
ข้อดีคือ Server สามารถสร้าง Entity:
แม้ไม่มี Player ยืนอยู่ตรงจุดนั้น
ได้
⑭ CreateVehicle ธรรมดาต่างอย่างไร
Cfx.re ระบุว่า Server RPC Entity Creation เช่น CreateVehicle ต้องมี Player ที่เหมาะสมอยู่ใน OneSync Focus Distance และการสร้างสามารถล้มเหลวได้ เช่น Client ที่ถูกเลือก Disconnect ระหว่างกระบวนการ.
ตัวอย่าง:
local vehicle = CreateVehicle(
`adder`,
x,
y,
z,
heading,
true
)
if vehicle == 0 then
print('Vehicle creation failed')
return
end
⑮ Server Setter เหมาะเมื่อไหร่
เหมาะเมื่อ:
ไม่มี Player อยู่ใกล้
Server ต้องเป็นผู้สร้าง Entity
Entity เป็นส่วนหนึ่งของ Server-controlled System
ต้องสร้าง Entity ก่อน Player เข้า Scope
ใช้ร่วมกับ Routing Bucket
ใช้กับ Server-managed Runtime Entity
Cfx.re แนะนำ Server Setter Natives สำหรับกรณีที่ต้องการ Server-side Entity Creation โดยไม่พึ่ง Nearby Client.
⑯ Entity ถูก Register แต่ยังไม่เห็นในเกมเกิดจากอะไร
Server Setter Entity อาจอยู่ในสถานะ:
Registered
+
Orphaned
ดังนั้น Server รู้จัก Entity แล้ว แต่ยังไม่มี Client Simulate Entity ใน World.
ควรตรวจ:
Player อยู่ใกล้ไหม
Player อยู่ Bucket ไหน
Entity อยู่ Bucket ไหน
Owner = -1 หรือไม่
Entity ยัง Exists หรือไม่
⑰ Routing Bucket มีผลหรือไม่
มีมาก
Routing Bucket แยก Player และ Entity เป็น Game State ต่างกัน และ Cfx.re ระบุว่า Player จะเห็น Entities/Players ที่อยู่ Bucket เดียวกันตาม Routing System.
ตัวอย่างปัญหา:
Player Bucket = 100
Vehicle Bucket = 0
Player อาจไม่เห็นรถแม้ Server ยังมี Entity อยู่
⑱ Server-created Entity ใน Instance ทำอย่างไร
ตัวอย่าง:
local bucket = 100
local vehicle = CreateVehicleServerSetter(
GetHashKey('blista'),
'automobile',
x,
y,
z,
heading
)
if vehicle == 0 then
return
end
SetEntityOrphanMode(
vehicle,
2
)
SetEntityRoutingBucket(
vehicle,
bucket
)
จากนั้น Player ที่ต้องเห็น Vehicle ต้องอยู่ใน Routing Bucket ที่เหมาะสมด้วย.
⑲ SetEntityOrphanMode แทน Routing Bucket ได้ไหม
ไม่ได้
จำ:
Orphan Mode
= Entity Lifecycle
Routing Bucket
= Entity อยู่ Instance ไหน
สองระบบทำงานคนละหน้าที่
⑳ SetEntityOrphanMode แทน Network ID ได้ไหม
ไม่ได้เช่นกัน
Network ID
= ใช้อ้าง Network Entity
Orphan Mode
= กำหนด Lifecycle Policy
เมื่อต้องส่ง Entity Reference ข้าม Client/Server ยังต้องใช้ Network ID ตาม Network Architecture
㉑ Orphan Mode กับ Entity Ownership ต่างกันอย่างไร
Entity Ownership
บอกว่า:
Client คนไหนกำลังเป็น Owner
Orphan Mode
บอกว่า:
Server ควรจัดการ Entity อย่างไรเมื่อไม่มี Owner ที่เหมาะสม
จึงไม่ควรสับสนสองแนวคิดนี้
㉒ Owner เปลี่ยนได้ไหม
ได้
OneSync ระบุว่า Entity ที่ออกนอก Range สามารถถูก Culled และ Migrated/Disowned ได้.
ดังนั้น Resource ไม่ควรคิดว่า:
Owner ตอน Spawn
=
Owner ตลอดอายุ Entity
㉓ SetEntityOrphanMode ล็อก Owner ไว้หรือไม่
ไม่ควรมองแบบนั้น
KeepEntity มีหน้าที่เรื่อง Server-side Persistence/Cleanup ไม่ใช่การกำหนด Static Network Owner
Ownership ยังถูก OneSync จัดการตาม Scope และ Networking Conditions.
㉔ RPC Native คืออะไร
Cfx.re ระบุว่า RPC Natives บางตัวฝั่ง Server จะถูกส่งไป Execute ที่ Client ซึ่งโดยทั่วไปคือ Client ที่เป็น Entity Owner และการเรียกเหล่านี้ อาจล้มเหลวได้.
ตัวอย่างแนวคิด:
Server
↓
RPC Native
↓
Current Client Owner
↓
Execute
㉕ ทำไม RPC Native ไม่ทำงานตอน Entity Orphaned
เพราะยังไม่มี Suitable Client Owner ที่จะรับ RPC
Cfx.re ระบุว่าระหว่าง Entity ยัง Orphaned Server RPC Native อย่าง SET_VEHICLE_COLOURS อาจไม่ทำงาน ขณะที่ Simple Server-side Getter บางตัวสามารถทำงานได้.
㉖ ตัวอย่างอาการ
Server:
local vehicle = CreateVehicleServerSetter(
`blista`,
'automobile',
coords,
0.0
)
SetVehicleColours(
vehicle,
4,
3
)
ถ้า Entity ยัง Orphaned Setter แบบ RPC อาจไม่ Apply ตามที่คาด.
㉗ วิธี Initialize Server-created Entity ที่ Cfx.re แนะนำ
Documentation แนะนำ Pattern:
Server Setter
↓
State Bag
↓
Client รับ Ownership
↓
State Bag Handler
↓
Initialize Entity
เพื่อหลีกเลี่ยงการเรียก RPC Setter ในช่วงที่ Entity ยังไม่มี Owner.
㉘ ตัวอย่าง State Bag Initialization
server.lua
local heli = CreateVehicleServerSetter(
`seasparrow`,
'heli',
coords,
0.0
)
Entity(heli).state:set(
'myresource:initVehicle',
true,
true
)
Cfx.re แสดง Pattern ลักษณะนี้ใน Migration Documentation.
㉙ Client รับ State Bag อย่างไร
แนวคิด:
AddStateBagChangeHandler(
'myresource:initVehicle',
nil,
function(bagName, key, value)
if not value then
return
end
local entity =
GetEntityFromStateBagName(
bagName
)
if entity == 0 then
return
end
-- Initialize entity
end
)
Cfx.re แนะนำ State Bag Handler สำหรับ Initialization ของ Server Setter Entity เมื่อ Client รับ Ownership.
㉚ ต้องตรวจ Owner ใน Change Handler ไหม
ใน Official Pattern มีการตรวจว่า Client ปัจจุบันเป็น Owner ของ Entity ก่อนทำ Initialization เพราะ Ownership สามารถเปลี่ยนรวดเร็วเมื่อมี Clients หลายคนอยู่ใกล้ Entity.
แนวคิด:
if NetworkGetEntityOwner(entity) ~= PlayerId() then
return
end
㉛ ทำไม Ownership เปลี่ยนเร็วเป็นปัญหา
Cfx.re ระบุว่าหาก Clients หลายคนอยู่ใกล้ Entity ตอนสร้าง Ownership อาจเปลี่ยนอย่างรวดเร็ว และมี Rare Reliability Cases ที่การเปลี่ยนแปลงจาก Initialization Handler ยังไม่ Sync กลับ Server ก่อน Owner เปลี่ยนอีกครั้ง.
จึงควรตรวจผล Server-side หลัง Initialization สำหรับ State สำคัญ
㉜ ควร Verify Initialization ไหม
ควรสำหรับระบบสำคัญ
Cfx.re แนะนำให้มีกลไกตรวจว่าการเปลี่ยนแปลงถูก Apply จริงฝั่ง Server และหากล้มเหลวหลังระยะเวลาหนึ่ง อาจต้องสร้าง Vehicle ใหม่ตาม Architecture.
แนวคิด:
Create
↓
Initialize
↓
Verify
↓
สำเร็จ → ใช้งาน
ไม่สำเร็จ
↓
Cleanup/Recreate
㉝ SetEntityOrphanMode ป้องกัน Client Delete ได้ไหม
ไม่ทั้งหมด
นี่เป็นข้อสำคัญมาก
Cfx.re ระบุว่า KeepEntity รับประกันว่า Server จะไม่ลบ Entity ด้วย Policy ที่เกี่ยวข้อง แต่ Client ยังสามารถ Request การลบ Entity ได้.
ดังนั้นอย่าคิดว่า:
SetEntityOrphanMode(entity, 2)
=
ไม่มีใครลบ Entity ได้
㉞ Server Owner ควรมี Delete Policy ของตัวเองไหม
ควร
Server-managed Entity ควรมีระบบกำหนดว่าใครมีสิทธิ์ขอ Delete
ตัวอย่าง:
Client ขอ Delete
↓
Server ตรวจ source
↓
ตรวจ Entity
↓
ตรวจ Session
↓
ตรวจ Permission
↓
Server Delete
ไม่ควรเปิด Network Event ที่รับ NetID แล้ว Delete ทันทีโดยไม่มี Validation
㉟ Client ส่ง NetID มาให้ Server ลบ ควรเชื่อไหม
ไม่
NetID เป็นเพียง Entity Reference
ไม่ใช่ Permission
Server ควรตรวจ:
Entity มีจริงหรือไม่
Resource เป็นเจ้าของ Entity หรือไม่
Player มีสิทธิ์หรือไม่
Player อยู่ Session เดียวกันหรือไม่
Entity State ถูกต้องหรือไม่
ก่อน DeleteEntity
㊱ SetEntityOrphanMode กับ Entity Lockdown ต่างกันอย่างไร
SetEntityOrphanMode
ควบคุม Lifecycle/Cleanup
Entity Lockdown
ควบคุมว่า Client สร้าง Entity ได้หรือไม่
OneSync รองรับ Entity Lockdown แยกตาม Routing Bucket และ strict หมายถึง Clients ไม่สามารถสร้าง Entities ได้เลยใน Bucket นั้น.
㊲ ใช้ Orphan Mode กับ strict Lockdown ได้ไหม
ได้
Architecture ที่เหมาะสม:
Routing Bucket strict
↓
Client สร้าง Entity ไม่ได้
↓
Server สร้าง Entity
↓
SetEntityOrphanMode(entity, 2)
↓
Set Entity Bucket
↓
State Bag Initialization
เป็นแนวทางที่สอดคล้องกับ Server-created Entity Best Practices ของ OneSync.
㊳ Population เกี่ยวข้องไหม
Routing Bucket สามารถเปิด/ปิด Population แยกต่างหากได้ และเป็นคนละ Setting กับ Orphan Mode.
ตัวอย่าง:
SetRoutingBucketPopulationEnabled(
bucket,
false
)
เหมาะกับ Private Instance ที่ต้องการให้ Server ควบคุม Environment เอง
㊴ Orphan Mode กับ sv_filterRequestControl ต่างกันอย่างไร
Orphan Mode
จัดการ Server Cleanup/Persistence ของ Entity
sv_filterRequestControl
จัดการ Client Control Request Policy
เป็นคนละ Layer
การที่ Entity เป็น KeepEntity ไม่ได้หมายความว่า Client ทุกคนจะสามารถ Request Control ได้
㊵ KeepEntity ทำให้ NetworkRequestControlOfEntity สำเร็จไหม
ไม่ควรคาดหวังเช่นนั้น
Network Control ยังขึ้นกับ:
Scope
Current Owner
Routing Bucket
Entity Lockdown
Request Control Policy
Orphan Mode ไม่ได้แทน Network Ownership System
㊶ Server-created Entity ยังออกนอก Scope ได้ไหม
ได้
OneSync ใช้ Culling เพื่อลดข้อมูลที่ Clients ไม่จำเป็นต้องรับ และ Entity ที่ออกนอก Range สามารถถูก Culled และ Migrated/Disowned ได้.
KeepEntity มีไว้ช่วยรักษา Server Entity Lifecycle ไม่ใช่ Force Streaming Entity ให้ Client ทุกคนตลอดเวลา
㊷ KeepEntity Force Entity ให้ทุกคนเห็นไหม
ไม่
Visibility ยังขึ้นกับ OneSync Scope และ Routing Bucket
ดังนั้น:
KeepEntity
≠
Always streamed to every client
ถ้ารถอยู่ห่าง Player มาก Client อาจไม่มี Local Entity แม้ Server ยังเก็บ Entity อยู่
㊸ Entity อยู่ Server แต่ Client หา NetID ไม่เจอ
เป็นไปได้จาก Scope
Server-side Entity ยัง Exists แต่ Client ไม่มี Local Representation
Resource ต้องออกแบบให้รองรับ:
Entity enters scope
Entity leaves scope
Owner migration
แทนการคิดว่า Entity ต้องมีทุก Client ตลอดเวลา
㊹ ควร Cache Entity Handle ไหม
ฝั่ง Serverสามารถเก็บ Entity Handle สำหรับ Runtime Management ได้ แต่ต้องตรวจ DoesEntityExist() ก่อนใช้งานหาก Entity อาจถูกลบไปแล้ว
ตัวอย่าง:
if not DoesEntityExist(entity) then
ManagedEntities[id] = nil
return
end
อย่าเก็บ Handle แล้วถือว่าถาวรตลอด Session
㊺ ควรเก็บ NetID ใน Database ไหม
ไม่ควรใช้เป็น Persistent Identity
NetID เป็น Runtime Network Reference
Persistent Entity ควรมี Database ID ของตัวเอง เช่น:
vehicle_id = 5824
แล้ว Map ไปยัง Runtime:
Entity Handle
NetID
เมื่อ Entity ถูกสร้าง
㊻ ตัวอย่าง Registry ที่ดีกว่า
ManagedVehicles[vehicleId] = {
entity = vehicle,
netId = NetworkGetNetworkIdFromEntity(
vehicle
),
bucket = bucket
}
โดย vehicleId เป็น ID ของระบบเอง ไม่ใช่ NetID
เมื่อ Entity ถูกลบต้อง Cleanup Registry
㊼ entityRemoved ช่วยอะไร
FiveM มี Server Event สำหรับตรวจ Entity Removal
Resource สามารถใช้ Event Lifecycle เพื่อล้าง Reference ของ Entity ที่ตัวเองดูแล
แนวคิด:
AddEventHandler(
'entityRemoved',
function(entity)
-- Remove stale reference
end
)
ช่วยลดปัญหา Table เก็บ Entity ที่ไม่มีอยู่แล้ว
㊽ Resource Stop ควรทำอย่างไร
หาก Resource สร้าง Temporary Server Entities เอง ควรมี Cleanup Strategy
ตัวอย่าง:
AddEventHandler(
'onResourceStop',
function(resourceName)
if resourceName ~=
GetCurrentResourceName() then
return
end
-- Cleanup managed entities
end
)
KeepEntity ไม่ได้หมายความว่าควรปล่อย Entity ของ Resource ค้างหลัง Resource หยุด
㊾ KeepEntity กับ Cleanup ขัดกันไหม
ไม่
สองอย่างควรทำงานร่วมกัน:
ระหว่าง Resource ทำงาน
→ KeepEntity ป้องกัน Entity หายโดยไม่ตั้งใจ
เมื่อ Resource ไม่ต้องการ Entityแล้ว
→ Resource Cleanup อย่างตั้งใจ
นี่คือ Lifecycle ที่เหมาะสมกว่า “สร้างแล้วไม่ลบเลย”
㊿ Checklist SetEntityOrphanMode
ก่อนใช้ Production ตรวจว่า:
Entity ถูกสร้างจาก Server หรือไม่
ใช้ Server Setter หรือ RPC Creation
ตรวจ Entity Creation Result
รู้ว่า Entity อาจเริ่ม Orphaned
เข้าใจ Owner
-1ใช้ Mode
2เมื่อ KeepEntity เหมาะสมไม่คิด KeepEntity = Database Persistence
ไม่คิด KeepEntity = Client ลบไม่ได้
ไม่คิด KeepEntity = Static Owner
ไม่คิด KeepEntity = Force Streaming
ตรวจ Routing Bucket
ตรวจ Player Bucket
ตรวจ Scope
ตรวจ Current Owner
ระวัง RPC Native ตอน Entity Orphaned
ใช้ State Bag Initialization เมื่อเหมาะสม
Verify Initialization
ใช้ NetID สำหรับ Network Reference
ใช้ Database ID สำหรับ Persistent Identity
มี Entity Registry
Cleanup Stale Handles
Cleanup เมื่อ Entity ถูก Remove
Cleanup เมื่อ Resource Stop
Cleanup เมื่อ Session จบ
ตรวจ Client Delete Policy
Validate Delete Events
ทดสอบ Owner Migration
ทดสอบไม่มี Player ใกล้ Entity
ทดสอบ Routing Bucket
ตรวจ Server Console และ Client F8
51. ตัวอย่าง Server-created Vehicle แบบครบ
local ManagedVehicles = {}
local function createManagedVehicle(
id,
model,
vehicleType,
coords,
heading,
bucket
)
local vehicle =
CreateVehicleServerSetter(
GetHashKey(model),
vehicleType,
coords.x,
coords.y,
coords.z,
heading
)
if vehicle == 0 then
return nil
end
SetEntityOrphanMode(
vehicle,
2
)
if bucket then
SetEntityRoutingBucket(
vehicle,
bucket
)
end
ManagedVehicles[id] = {
entity = vehicle,
netId =
NetworkGetNetworkIdFromEntity(
vehicle
),
bucket = bucket
}
return vehicle
end
โครงสร้างนี้ใช้แนวคิด Server Setter + KeepEntity + Routing Bucket ตามระบบ OneSync.
52. ตัวอย่าง State Bag Initialization
local vehicle =
CreateVehicleServerSetter(
`blista`,
'automobile',
coords,
heading
)
if vehicle == 0 then
return
end
SetEntityOrphanMode(
vehicle,
2
)
local state =
Entity(vehicle).state
state:set(
'myvehicle:init',
true,
true
)
Server Setter + State Bag Initialization เป็น Pattern ที่ Cfx.re แนะนำสำหรับ Entity ที่อาจยังไม่มี Owner ทันที.
53. ตัวอย่าง Wait Owner แบบมี Timeout
หากระบบจำเป็นต้องรู้ว่า Entity มี Owner แล้ว:
local function waitForOwner(
entity,
timeoutMs
)
local expires =
GetGameTimer() + timeoutMs
while GetGameTimer() < expires do
if not DoesEntityExist(entity) then
return nil
end
local owner =
NetworkGetEntityOwner(entity)
if owner ~= -1 then
return owner
end
Wait(100)
end
return nil
end
อย่าใช้ Loop ที่ไม่มี Timeout เพราะ Entity อาจไม่มี Suitable Client อยู่ใน Scope เป็นเวลานาน
54. ตัวอย่าง Cleanup Vehicle
local function removeManagedVehicle(id)
local data =
ManagedVehicles[id]
if not data then
return
end
if DoesEntityExist(data.entity) then
DeleteEntity(data.entity)
end
ManagedVehicles[id] = nil
end
KeepEntity ไม่ได้ห้าม Resource ลบ Entity ที่ตัวเองไม่ต้องการแล้ว
55. Entity หายทั้งที่ตั้ง OrphanMode 2 เพราะอะไร
ให้ตรวจหลายสาเหตุ ไม่ใช่สรุปว่า Native ไม่ทำงานทันที:
Resource เรียก DeleteEntity?
Client Request Delete?
Session Cleanup?
Resource Restart?
Server Restart?
Entity Lifecycle Code?
Routing/Spawn Logic?
Cfx.re ระบุเองว่า KeepEntity ป้องกัน Server-side Removal ตาม Policy นี้ แต่ Client ยังสามารถ Request Deletion ได้.
56. Vehicle หายเมื่อไม่มี Player อยู่ใกล้
ถ้าเป็น Server Setter + KeepEntity Server สามารถเก็บ Entity Registration ไว้ได้แม้ไม่มี Client Suitable Owner แต่ Entity จะไม่ถูก Simulate ใน Game World จนมี Client ที่เหมาะสมอยู่ใน Scope.
จึงต้องแยก:
Entity ยังอยู่ใน Server State
กับ:
Client กำลัง Render/Simulate Entity
57. Ped ยืนนิ่งหลังสร้างจาก Server
ตรวจว่า:
Owner = -1 หรือไม่
Player อยู่ใน Scope หรือไม่
Routing Bucket ถูกหรือไม่
Task เป็น RPC Native หรือไม่
State Bag Initialization ทำงานหรือไม่
ถ้า Entity ยัง Orphaned Client Simulation และ RPC Operations บางอย่างอาจยังไม่พร้อม.
58. Vehicle สีไม่เปลี่ยนหลัง Spawn
Cfx.re ยก Vehicle Colour Setter เป็นตัวอย่างโดยตรงว่าการเรียก Server RPC Setter ขณะ Entity ยัง Orphaned อาจไม่ทำงาน.
ให้พิจารณา:
State Bag Initialization
+
Client Owner applies appearance
+
Server Verify
แทนการเรียก Setter ทันทีหลัง Server Setter Creation
59. Routing Bucket รถถูกสร้างแต่ไม่เห็น
ตรวจ:
local entityBucket =
GetEntityRoutingBucket(vehicle)
local playerBucket =
GetPlayerRoutingBucket(source)
ถ้าควรอยู่ Instance เดียวกันแต่เลขไม่ตรง ให้แก้ Routing Assignment ก่อน
KeepEntity ไม่ได้แก้ Routing Visibility
60. Orphan Mode ควรใช้กับ Entity ทุกตัวไหม
ไม่จำเป็น
Temporary Entity ที่ต้องอยู่เพียงช่วงสั้นๆ อาจไม่ต้อง KeepEntity
ตัวอย่าง:
Temporary Visual Object
Short-lived Gameplay Entity
Entity ที่ควร Cleanup เมื่อไม่มี Playerเกี่ยวข้อง
การตั้ง KeepEntity ให้ทุก Entity โดยไม่จำเป็นอาจทำให้ Resource ต้องรับภาระ Cleanup มากขึ้น
61. Entity Lifecycle ที่ดีควรเป็นอย่างไร
Create
↓
Register
↓
Set Orphan Policy
↓
Set Bucket
↓
Set State
↓
Use
↓
Track
↓
Cleanup
อย่าหยุดที่:
Create
↓
Forget
เพราะ Server ที่เปิดนานสามารถสะสม Entity ที่ไม่ใช้แล้วได้
62. Server Owner ควรมี Entity Manager ไหม
หากมีระบบ Persistent/Managed Entities จำนวนมาก ควรมี Registry หรือ Entity Manager กลาง
ตัวอย่างข้อมูล:
Internal ID
Entity Handle
NetID
Type
Routing Bucket
Owner Resource
Created Time
State
ช่วย Debug และ Cleanup ได้ง่ายกว่า Resource แต่ละตัวสร้าง Entity โดยไม่มีการติดตาม
63. SetEntityOrphanMode ใช้กับ Database อย่างไร
Database ควรเก็บ ข้อมูลที่ใช้สร้าง Entityใหม่
ตัวอย่าง:
Database
vehicle_id = 5824
model = blista
x/y/z
heading
locked = true
↓ Server Start
CreateVehicleServerSetter
↓
SetEntityOrphanMode(..., 2)
↓
Runtime Entity
↓
Runtime NetID
เมื่อ Server Restart NetID ใหม่อาจแตกต่างจากเดิม
64. อย่าเก็บ Entity Handle ลง Database
Entity Handle เป็น Runtime Reference
ดังนั้นไม่ควร:
database.entity_handle = 394821
แล้วนำกลับมาใช้หลัง Server Restart
ให้เก็บ Persistent Record ID แล้ว Resolve Runtime Entity ใหม่แทน
65. สูตรจำ SetEntityOrphanMode
จำเพียง 4 Layer:
Database ID
= ตัวตนถาวร
NetID
= ตัวตนใน Network Runtime
Owner
= Client ที่กำลังควบคุม
Orphan Mode
= Server Lifecycle Policy
หากแยก 4 อย่างนี้ออกจากกันได้ จะเข้าใจ Persistent Entity Architecture ของ FiveM ง่ายขึ้นมาก
FAQ FiveM SetEntityOrphanMode
FiveM SetEntityOrphanMode คืออะไร
เป็น Server Native สำหรับกำหนด Orphan Behavior ของ Entity และ Cfx.re แนะนำใช้ KeepEntity กับ Server-created Entities ที่ไม่ต้องการให้ Server Cleanup ตาม Orphan Policy.
SetEntityOrphanMode(entity, 2) คืออะไร
Mode 2 คือ KeepEntity ตาม OneSync Documentation.
KeepEntity ทำให้รถอยู่หลัง Server Restart ไหม
ไม่ Entity ยังเป็น Runtime Entity หากต้องกลับมาหลัง Restart ต้องเก็บข้อมูลถาวรและสร้าง Entity ใหม่
KeepEntity ป้องกัน Client ลบ Entity ได้ไหม
ไม่ทั้งหมด Cfx.re ระบุว่า Server จะไม่ลบ Entityจาก Policy นี้ แต่ Client ยังสามารถ Request Deletion ได้.
NetworkGetEntityOwner ได้ -1 หมายความว่าอะไร
สำหรับ Server Setter Entity อาจหมายความว่า Entity ยัง Orphaned และยังไม่มี Suitable Client Owner.
Entity Orphaned ยังมีอยู่บน Server ไหม
Server Setter Register Entity กับ Server แล้ว แต่ Entityยังไม่ถูก Simulate ใน Game World จนมี Client ที่เหมาะสมเข้ามาใน Scope.
ทำไม RPC Native ไม่ทำงานกับ Orphaned Entity
เพราะ RPC Native ต้องทำงานผ่าน Client Owner และระหว่าง Orphaned ยังไม่มี Owner ที่เหมาะสม.
State Bags ช่วย Server-created Entity อย่างไร
Cfx.re แนะนำ State Bag Initialization เพื่อให้ Client ที่รับ Ownership ทำ Initialization ที่จำเป็นหลัง Entityพร้อมแล้ว.
SetEntityOrphanMode ใช้กับ Routing Bucket ได้ไหม
ได้ เป็นคนละระบบ สามารถตั้ง KeepEntity แล้วกำหนด Entity Routing Bucket เพิ่มตาม Instance Architecture.
Server-created Entity ทุกตัวต้องใช้ KeepEntity ไหม
ไม่ ต้องเลือกตาม Lifecycle ของ Entity ถ้าเป็น Temporary Entity และควรหายเมื่อไม่มีผู้เล่นเกี่ยวข้อง การ KeepEntity อาจไม่จำเป็น
ประเด็นสำคัญ
FiveM SetEntityOrphanMode มีหน้าที่จัดการ Server-side Lifecycle ของ Networked Entity และ Cfx.re แนะนำ SetEntityOrphanMode(entity, 2) หรือ KeepEntity สำหรับ Server-created Entity ที่ต้องการป้องกันไม่ให้ Server Remove จาก Orphan Cleanup.
แต่ KeepEntity ไม่ใช่ Database Persistence, ไม่ได้ล็อก Network Owner, ไม่ได้ Force Entity ให้อยู่ใน Scope ของ Client ทุกคน และไม่ได้รับประกันว่า Client จะไม่สามารถ Request ลบ Entity ได้.
Server Setter Entity ยังสามารถเริ่มในสถานะ Orphaned ซึ่ง NetworkGetEntityOwner() จะคืน -1 และ Server RPC Natives บางตัวจะยังไม่ทำงานจนมี Suitable Client อยู่ใน Scope.
สำหรับ Initialization ที่ต้องพึ่ง Client Cfx.re แนะนำ Pattern Server Setter → State Bag → Client Owner → Initialize → Verify และเตือนว่า Ownership สามารถเปลี่ยนอย่างรวดเร็วเมื่อมี Clients หลายคนอยู่ใกล้ Entity.
ดังนั้นสำหรับผู้อ่าน comsiam ให้จำว่า “KeepEntity = ป้องกัน Server Cleanup ไม่ใช่ Save ลง Database” และ comsiam แนะนำให้ Server ที่มี Persistent Vehicles, NPCs หรือ Objects ออกแบบ Entity Lifecycle ให้ครบทั้ง Create → Keep → Track → Verify → Cleanup พร้อมแยก Database ID, NetID, Owner และ Orphan Mode ออกจากกันอย่างชัดเจน
Comments
Post a Comment