FiveM State Bags คืออะไร? วิธี Sync ข้อมูลระหว่าง Server, Client และ Entity อย่างถูกต้อง
FiveM State Bags คือระบบเก็บและ Synchronize ค่าแบบ Key/Value ที่ผูกกับ Entity, Player หรือ Global State โดย Cfx.re ระบุว่าใน State Awareness Mode แต่ละ Entity สามารถมีชุดข้อมูล State ของตัวเอง และ Clients ที่เกี่ยวข้องสามารถเข้าถึงค่าที่ถูก Replicate ได้.
State Bags เหมาะกับข้อมูลประเภท “สถานะปัจจุบัน” เช่น รถคันนี้ล็อกหรือไม่, Player อยู่ในสถานะอะไร หรือ Feature ระดับ Server เปิดอยู่หรือไม่ โดยช่วยลดการเขียน Network Event ซ้ำๆ สำหรับ State ที่ต้อง Synchronize ต่อเนื่อง
Meta SEO
Meta Title: FiveM State Bags คืออะไร? วิธี Sync ข้อมูล Server Client และ Entity
Meta Description: อธิบาย FiveM State Bags แบบละเอียด Entity.state, Player.state, GlobalState, Replication และ AddStateBagChangeHandler พร้อมตัวอย่าง Lua และวิธีแก้ State ไม่ Sync
Focus Keyword: FiveM State Bags
Related Keywords: FiveM Entity State, FiveM Player State, FiveM GlobalState, AddStateBagChangeHandler, FiveM OneSync, FiveM State Synchronization
สารบัญ
① FiveM State Bags คืออะไร
Cfx.re อธิบายว่า State Bag คือชุด Key/Value Pairs ที่สามารถเชื่อมกับ Entity ใน State Awareness Mode ได้.
ตัวอย่างแนวคิด:
Vehicle
├── locked = true
├── fuel = 75
└── owner = 123
Player
├── duty = true
└── job = "police"
Global
└── moneyEnabled = true
แทนที่จะสร้าง Event สำหรับถามค่าทุกครั้ง Resource สามารถอ่าน State ที่เกี่ยวข้องได้ตาม Context
② State Bag เป็น Database หรือไม่
ไม่ใช่ Database
State Bags เป็น Runtime State Synchronization ของ FiveM ไม่ใช่ Persistent Storage สำหรับเก็บ Character, เงิน หรือ Inventory หลัง Server ปิด
ดังนั้นข้อมูลที่ต้องอยู่ข้าม Server Restart ยังควรใช้ Persistent Storage ของระบบนั้น ส่วน State Bags เหมาะกับ State ที่ต้องใช้งานระหว่าง Runtime
③ State Bags เกี่ยวข้องกับ OneSync หรือไม่
เกี่ยวข้องกับระบบ State Awareness/Networking ของ FiveM และ OneSync Documentation แนะนำ State Bags สำหรับการกำหนด Attributes ให้ Entities เพื่อให้ Clients อื่นสามารถเข้าถึงข้อมูลดังกล่าวได้.
จึงพบ State Bags มากใน Resources ที่ต้อง Sync สถานะของ Networked Entities
④ Entity State คืออะไร
Entity เช่น Vehicle, Ped หรือ Object สามารถมี State Bag ของตัวเอง
ตัวอย่าง Lua จากแนวทาง Cfx.re:
local vehicle = GetVehiclePedIsIn(ped, false)
local state = Entity(vehicle).state
print(state.mollis)
Cfx.re ระบุว่า Entity State สามารถเข้าถึงผ่าน:
Entity(entity).state
⑤ ตั้ง Entity State อย่างไร
ตัวอย่าง:
Entity(vehicle).state.locked = true
หรือ:
Entity(vehicle).state.fuel = 75
อย่างไรก็ตาม Cfx.re ระบุว่า Entity State สามารถถูกเขียนได้โดย Entity Owner หรือ Server ตาม Policy ปกติ.
⑥ ตัวอย่าง State รถ FiveM
local vehicle = GetVehiclePedIsIn(PlayerPedId(), false)
if vehicle ~= 0 then
Entity(vehicle).state.fuel = 80
end
แนวคิดคือ State fuel ถูกผูกกับ Vehicle Entity นั้น
แต่ถ้า Resource ต้องการ Authoritative State ควรพิจารณาว่า State ควรถูกกำหนดจาก Server มากกว่า Client หรือไม่
⑦ Network Entity สำคัญอย่างไร
State Bag ของ Entity เหมาะกับ Entity ที่อยู่ภายใต้ระบบ Network Synchronization
OneSync Documentation ระบุว่า State Bags ใช้กำหนด Attributes ให้ Entities และทำให้ Clients อื่นสามารถอ่านข้อมูลเหล่านั้นได้ตาม Scope/Networking ของ Entity.
ดังนั้น Entity Ownership และ Scope ยังเป็นส่วนหนึ่งที่ต้องเข้าใจ
⑧ Player State คืออะไร
Players มี State Bag ของตัวเองเช่นกัน
Cfx.re ยกตัวอย่าง Client:
LocalPlayer.state.soviet = 'connection'
และฝั่ง Server:
local value = Player(source).state.testosterone
จึงสามารถใช้ Player State สำหรับสถานะ Runtime ที่ผูกกับผู้เล่น
⑨ ตัวอย่าง Player State
เช่น Resource ต้องการเก็บว่า Player อยู่ใน Duty หรือไม่
Server:
Player(source).state.duty = true
อีก Resource สามารถอ่าน:
local onDuty = Player(source).state.duty
ช่วยให้ Resources หลายตัวอ้างสถานะเดียวกันได้ง่ายกว่าการสร้าง State Table แยกทุก Resource
⑩ Player State ใช้แทน Database ได้ไหม
ไม่ควร
เช่น:
เงินในบัญชี
Inventory ถาวร
Character
Property
ไม่ควรพึ่ง Player State เป็น Storage ถาวร
State Bag เหมาะสำหรับ State Runtime ที่ต้อง Sync หรือแชร์ระหว่าง Scripts
⑪ GlobalState คืออะไร
Cfx.re ระบุว่า Global State เป็น State ที่ใช้ทั่ว Server โดย Server เป็นผู้กำหนด และ Client สามารถอ่านได้.
ตัวอย่าง Official:
GlobalState.moneyEnabled = true
จากนั้น Client Resource สามารถนำค่าดังกล่าวไปใช้ตาม Logic ของระบบ
⑫ GlobalState เหมาะกับอะไร
ตัวอย่าง:
Server Event เปิดหรือไม่
ระบบบาง Feature เปิดหรือไม่
Global Game Mode
Global Weather State ตาม Resource Architecture
เหมาะกับค่าที่หลาย Clients ต้องอ่านร่วมกัน
⑬ อย่าใส่ Secret ลง GlobalState
เนื่องจาก Global State มีไว้ให้ Client อ่านได้ตามรูปแบบที่ Cfx.re ระบุ จึงไม่ควรใช้เก็บ
Password
API Secret
Database Credential
Private Token
Secret ควรอยู่ฝั่ง Server เท่านั้น
⑭ State Bags Replicate อย่างไร
Cfx.re ระบุ Default Behavior ว่า:
State ที่ Server ตั้ง → Replicated
State ที่ Client ตั้ง → ไม่ Replicated โดย Default
และสามารถ Override เป็นราย State ด้วย Method set.
นี่เป็นจุดสำคัญมากในการ Debug State ที่ “เห็นเฉพาะเครื่องตัวเอง”
⑮ Server ตั้ง State แล้ว Client เห็นหรือไม่
โดย Default State ที่ตั้งจาก Server จะถูก Replicate.
ตัวอย่าง:
Entity(vehicle).state.fuel = 80
หากเรียกฝั่ง Server บน Entity ที่เกี่ยวข้อง State จะถูก Replicate ตามระบบ State Bag
⑯ Client ตั้ง State แล้ว Server เห็นหรือไม่
โดย Default State ที่ Client ตั้งจะ ไม่ Replicate แต่สามารถกำหนด Explicit Replication ผ่าน:
state:set(key, value, true)
ตาม API ที่ Cfx.re ระบุ.
⑰ Parameter ตัวที่สามของ state:set คืออะไร
ตัวอย่าง:
Entity(entity).state:set('taskAck', 'guard', true)
Parameter ที่สามกำหนดว่าการ Set นั้นต้อง Replicate หรือไม่.
จำง่ายๆ:
true = Replicate
false = Local
ตาม Context ของ State Set
⑱ ตัวอย่าง Server-only State
Cfx.re แสดงตัวอย่าง:
Entity(vehicle).state:set('clone', 600, false)
เพื่อให้ Server เก็บ State นั้นไว้โดยไม่ Replicate ออกไป.
เหมาะกับ State Internal ที่ Client ไม่จำเป็นต้องรู้
⑲ ตัวอย่าง Client ส่ง State กลับ Server
Cfx.re ยกตัวอย่าง:
Entity(enemy).state:set('taskAck', 'guard', true)
กรณี Client ต้องแจ้ง State บางอย่างกลับ Server โดยใช้ Replicated Set.
อย่างไรก็ตามข้อมูล Client-side ที่มีผลสำคัญต่อ Gameplay ยังควรถูก Validate ฝั่ง Server ไม่ควรเชื่อ Client โดยอัตโนมัติ
⑳ Local State ใช้ทำอะไร
State แบบไม่ Replicate เหมาะกับข้อมูลที่ Resource ต้องใช้เฉพาะ Context นั้น
ตัวอย่าง:
Entity(vehicle).state:set(
'localEffectLoaded',
true,
false
)
ช่วยแยก Local UI/Processing State ออกจาก State ที่ทุกฝ่ายต้อง Sync
㉑ State Bag Key ควรตั้งชื่ออย่างไร
ควรใช้ Key ที่ชัดเจน เช่น:
vehicleLocked
vehicleFuel
jobDuty
characterLoaded
garageOwner
หลีกเลี่ยง:
x
a
value
data
เพราะ Server ใหญ่สามารถมี Resources จำนวนมากและ Debug State ได้ยาก
㉒ ควรใส่ Resource Prefix ไหม
ถ้ามีโอกาสชนกับ Resource อื่น สามารถออกแบบ Key เช่น:
mygarage:locked
mygarage:owner
myjob:duty
ช่วยให้ทราบว่า Resource ใดเป็นเจ้าของ State
แนวทางนี้ยังเข้ากับคำแนะนำเรื่อง State แบบ Granular ของ Cfx.re ซึ่งใช้ตัวอย่าง Key เช่น x:y.
㉓ State Bags มีข้อจำกัดเรื่อง Nested Data
มี
Cfx.re ระบุว่า State Getters/Setters ปัจจุบันมี Shallow Limitations โดยทุก Get จะคืน Serialized State และการ Set ต้องเป็น Direct Set จึงจะ Serialize State กลับได้.
ตัวอย่างที่ Cfx.re ระบุว่า ไม่ Replicate:
Entity(x).state.x.y = 'b'
㉔ ทำไม Nested State ไม่ควรแก้แบบนี้
ตัวอย่าง:
Entity(vehicle).state.vehicleData.locked = true
อาจไม่สร้าง Replication ตามที่คาด เพราะเป็นการแก้ค่าซ้อนภายใน Table แทน Direct State Set
Cfx.re แนะนำการใช้ Granular Key มากกว่า.
㉕ วิธีแก้ Nested State
แทน:
Entity(vehicle).state.vehicle.locked = true
ใช้:
Entity(vehicle).state['vehicle:locked'] = true
Cfx.re ใช้แนวคิด:
Entity(x).state['x:y'] = 'b'
เป็นรูปแบบที่ Granular กว่า.
㉖ การอ่าน Nested State หลายครั้งอาจช้ากว่า
Cfx.re ยกตัวอย่างว่า:
local y = Entity(x).state.x.y
local z = Entity(x).state.x.z
ทำให้ State x ถูก Deserialize ซ้ำ และแนะนำให้ใช้ State Keys ที่ Granular มากกว่า.
จึงควรออกแบบ State Schema ตั้งแต่แรก
㉗ State Bag ควรเก็บ Table ใหญ่หรือไม่
ควรระวัง
State Bag เหมาะกับค่าที่ค่อนข้าง Granular มากกว่าการเก็บ Object ใหญ่แล้วอ่าน Sub-key ซ้ำๆ เพราะ Cfx.re ระบุข้อจำกัดด้าน Shallow Serialization ไว้อย่างชัดเจน.
ตัวอย่างที่ดีกว่า:
vehicle:fuel
vehicle:locked
vehicle:engine
แทน Table ใหญ่ชุดเดียวเมื่อไม่จำเป็น
㉘ AddStateBagChangeHandler คืออะไร
State Bag Change Handler ใช้ตรวจจับการเปลี่ยนแปลงของ State Bag
Cfx.re ระบุว่าเมื่อ State Change ถูกตรวจพบ Handler ที่เกี่ยวข้องสามารถถูกเรียกด้วยข้อมูล State ใหม่.
เหมาะกับ Logic แบบ:
State เปลี่ยน
↓
Handler ทำงาน
↓
Update Gameplay/UI/Entity
㉙ ทำไม Change Handler ดีกว่า Loop บางกรณี
ถ้าต้องการรู้เพียงว่า State เปลี่ยนเมื่อใด การใช้ Change Handler ช่วยหลีกเลี่ยงการ Loop ตรวจ State ทุก Tick โดยไม่จำเป็น
OneSync Documentation ยังแนะนำ State Bags สำหรับ Scoped Events แทน Events อย่าง playerEnteredScope/playerLeftScope ในหลายกรณี เพราะ Scope Events มี Scaling Performance Costs.
㉚ ตัวอย่าง Change Handler
แนวคิด Lua:
AddStateBagChangeHandler(
'vehicle:locked',
nil,
function(bagName, key, value)
print(('State changed: %s = %s')
:format(key, tostring(value)))
end
)
AddStateBagChangeHandler เป็น Native สำหรับเพิ่ม Handler ให้การเปลี่ยน State Bag.
㉛ Filter Key ได้ไหม
Change Handler รองรับการกำหนด Key Filter เพื่อให้ Handler สนใจเฉพาะ State Key ที่ต้องการ.
เช่น Resource สนใจเพียง:
vehicle:locked
ก็ไม่จำเป็นต้องทำ Logic กับ State Key ทุกตัว
㉜ Bag Name คืออะไร
State Bag ภายในสามารถอ้างถึงประเภทต่างๆ เช่น Entity หรือ Player
Native Reference มี Helpers สำหรับแปลง Bag Name กลับไปเป็น Entity หรือ Player เช่น GetEntityFromStateBagName และ GetPlayerFromStateBagName.
จึงสามารถใช้ Change Handler กับ Entity-specific Logic ได้
㉝ State Bags กับ TriggerClientEvent ต่างกันอย่างไร
TriggerClientEvent
เหมาะกับ “เหตุการณ์” เช่น:
เปิด Notification ตอนนี้
เปิด Menu ตอนนี้
เล่น Effect ตอนนี้
State Bag
เหมาะกับ “สถานะปัจจุบัน” เช่น:
รถล็อกอยู่หรือไม่
Player อยู่ Duty หรือไม่
Feature เปิดหรือไม่
State Bag ไม่ได้แทน Network Events ทุกประเภท แต่เหมาะกับ Data Synchronization ที่เป็น State
㉞ State Bags แทน Network Events ทั้งหมดได้ไหม
ไม่ได้
ถ้าเป็น Action แบบครั้งเดียว เช่น:
Player กดซื้อของ
Server ตอบผลการซื้อ
แสดง Notification
Network Event ยังเหมาะกว่า
แต่หากเป็นสถานะที่ Clients ต้องสามารถอ่านได้ต่อเนื่อง State Bag อาจเหมาะกว่า
㉟ เมื่อไหร่ควรใช้ State Bag
เหมาะเมื่อ:
State ผูกกับ Entity
State ผูกกับ Player
หลาย Resource ต้องอ่านค่าเดียวกัน
Client ที่เข้ามาใน Scope ต้องรู้ State
State เปลี่ยนเป็นครั้งคราว
ไม่ต้องการ Poll ทุก Tick
OneSync Documentation แนะนำ State Bags โดยเฉพาะกับ Scoped State/Entity Attributes.
㊱ เมื่อไหร่ควรใช้ Network Event
เหมาะกับ:
Request/Response
User Action
Notification
Transaction
One-time Gameplay Event
Commands
State และ Event จึงควรใช้ร่วมกันตามหน้าที่ ไม่ใช่เลือกเพียงระบบเดียว
㊲ State Bag กับ ConVar ต่างกันอย่างไร
ConVar
เหมาะกับ Configuration ของ Server/Resource เช่น:
featureEnabled
debugMode
locale
State Bag
เหมาะกับ Runtime State ของ Player/Entity/Global State
เช่น:
vehicleLocked
playerDuty
doorOpen
สองระบบมีเป้าหมายต่างกัน
㊳ sv_stateBagStrictMode คืออะไร
Server Commands ปัจจุบันของ Cfx.re มี ConVar:
setr sv_stateBagStrictMode true
เมื่อเปิด true จะกำหนดให้ เฉพาะ Server เท่านั้น ที่สามารถแก้ State ของ Networked Entities และ Player State ได้ ส่วน Client-side Non-replicated Entities ไม่ได้รับผลจาก Setting นี้.
㊴ Strict Mode Default เป็นอะไร
Cfx.re Documentation ปัจจุบันระบุ Default เป็น:
false
ซึ่งหมายความว่า Network Owner ยังสามารถแก้ State ของ Entity ที่ตนเป็น Owner และแก้ Player State ของตนได้.
㊵ เปิด Strict Mode แล้ว Client Set State ไม่ได้
หาก:
setr sv_stateBagStrictMode true
Client พยายามแก้ State ของ Replicated Entity ระบบจะ Reject การเปลี่ยนแปลงและ Client Console จะแสดง Error ที่เกี่ยวข้องกับ State Bag Strict Mode.
Resource ที่พึ่ง Client Replication จึงควรทดสอบ Compatibility ก่อนเปิด Setting นี้
㊶ Strict Mode ดีไหม
ขึ้นกับ Server Architecture
หากต้องการให้ Server เป็นผู้ควบคุม Authoritative State มากขึ้น Strict Mode สามารถช่วยจำกัด Client-side State Modification ได้
แต่ Resource ที่ออกแบบให้ Client Owner เขียน Replicated State อาจต้องปรับ Logic ก่อน เพราะ Default Policy และ Strict Mode มีพฤติกรรมต่างกัน.
㊷ State Bag Security ควรคิดอย่างไร
อย่าคิดว่า State ที่ Client ส่งขึ้นมาคือข้อมูลจริงเสมอ
สำหรับข้อมูลสำคัญ เช่น:
เงิน
Inventory
Permission
Reward
Ownership
ควรให้ Server เป็นผู้ตรวจ State จริงก่อนนำไปเปลี่ยนข้อมูลสำคัญ
State Bags เป็นเครื่องมือ Synchronization ไม่ใช่การแทน Server-side Validation
㊸ FiveM State Bag ไม่ Sync แก้อย่างไร
ตรวจตามลำดับ:
State ถูก Set ฝั่งไหน
Entity Networked หรือไม่
ใครเป็น Entity Owner
ใช้
.state.key = valueหรือ.state:set()Replicated Parameter เป็น
trueหรือไม่เปิด
sv_stateBagStrictModeหรือไม่Client/Server อยู่ Scope ที่เหมาะสมหรือไม่
Console มี Error หรือไม่
Cfx.re ระบุ Default Replication Rules และ Strict Mode ไว้โดยตรง จึงควรเริ่มจากสองจุดนี้ก่อน.
㊹ State เห็นเฉพาะ Client ตัวเอง
ถ้า Client Set:
Entity(entity).state.myState = true
Default Client-set State ไม่ถูก Replicate.
หาก Architecture ต้องการ Replicate และ Policy อนุญาต อาจใช้:
Entity(entity).state:set(
'myState',
true,
true
)
แต่ข้อมูลสำคัญควรให้ Server เป็นผู้ตรวจ/กำหนด
㊺ Client Set แล้วขึ้น Strict Mode Error
ตรวจ server.cfg ว่ามี:
setr sv_stateBagStrictMode true
หรือไม่
เมื่อเปิด Setting นี้ Cfx.re ระบุว่า Client ไม่สามารถแก้ State ของ Replicated Entities/Player State ผ่าน Network ได้.
ต้องปรับ Resource ให้ Server เป็นผู้ Set State หรือเปลี่ยน Architecture ตาม Requirement
㊻ Nested State เปลี่ยนแต่ไม่ Replicate
ถ้ามี:
Entity(entity).state.data.locked = true
ให้เปลี่ยนเป็น Direct/Granular State เช่น:
Entity(entity).state['data:locked'] = true
เพราะ Cfx.re ระบุว่าการแก้ Nested Value โดยตรงจะไม่ Replicate และแนะนำ Granular Keys.
㊼ State อ่านช้าเมื่อเรียกหลาย Sub-key
หลีกเลี่ยง:
local fuel = Entity(entity).state.data.fuel
local locked = Entity(entity).state.data.locked
เพราะ Cfx.re ระบุว่า State Getter สามารถ Deserialize ข้อมูลชุดเดิมซ้ำ.
ออกแบบเป็น:
vehicle:fuel
vehicle:locked
จะเหมาะกับข้อจำกัดปัจจุบันมากกว่า
㊽ Change Handler ไม่ทำงาน
ตรวจ:
Key Filter
Bag Filter
Resource Start
Handler Syntax
State เปลี่ยนจริงหรือไม่
State อยู่ Client หรือ Server
Entity อยู่ใน Context ที่ Handler มองเห็นหรือไม่
AddStateBagChangeHandler ถูกออกแบบให้ติดตามการเปลี่ยนแปลงของ State Bag ตาม Filters ที่กำหนด.
㊾ State Bag ใช้กับ Entity ที่ถูก Delete แล้วได้ไหม
State ผูกกับ Entity ดังนั้น Resource ไม่ควรเก็บ Entity Handle แล้วคิดว่า State จะเป็น Persistent Storage หลัง Entity Lifecycle จบ
หากข้อมูลต้องอยู่ต่อแม้ Entity ถูกลบ ควรเก็บ State ถาวรในระบบอื่นและสร้าง State Bag ใหม่เมื่อสร้าง Entity ใหม่
㊿ Checklist FiveM State Bags สำหรับ Developer
ตรวจว่า:
รู้ว่า State เป็น Entity/Player/Global
State Key ตั้งชื่อชัดเจน
ไม่เก็บ Secret ใน Replicated State
Server เป็น Authority สำหรับข้อมูลสำคัญ
เข้าใจ Default Replication
เข้าใจ
state:set()เข้าใจ Parameter Replicated
ไม่แก้ Nested Table โดยตรง
ใช้ Granular Keys
ไม่อ่าน Nested State ซ้ำโดยไม่จำเป็น
ใช้ Change Handler เมื่อเหมาะสม
ไม่ Poll ทุก Tick หากไม่จำเป็น
ตรวจ Entity Ownership
ตรวจ Scope
ตรวจ Strict Mode
ใช้ Network Events สำหรับ Actions
ใช้ State Bags สำหรับ State
ไม่ใช้เป็น Database
ทดสอบผู้เล่นหลายคน
ดู Client/Server Console เมื่อ State ไม่ Sync
ตาราง State Bag ที่ควรรู้
| ประเภท | ตัวอย่าง | จุดประสงค์ |
|---|---|---|
| Entity State | Entity(vehicle).state | State ของ Entity |
| Player State | Player(source).state | State ของ Player |
| Local Player State | LocalPlayer.state | Player State ฝั่ง Client |
| Global State | GlobalState | State ระดับ Server |
state:set() | Set พร้อมกำหนด Replication | ควบคุม Local/Replicated |
| Change Handler | AddStateBagChangeHandler | ฟัง State Change |
| Strict Mode | sv_stateBagStrictMode | จำกัด Client State Modification |
ความสามารถเหล่านี้อ้างอิงจาก State Bags และ Server Commands Documentation ปัจจุบันของ Cfx.re.
ตัวอย่าง Entity State จาก Server
RegisterNetEvent('garage:setVehicleLocked', function(netId, locked)
local src = source
local entity = NetworkGetEntityFromNetworkId(netId)
if entity == 0 then
return
end
-- Production Resource ควรตรวจ ownership/permission
-- และสิทธิ์ของผู้เล่นก่อนเปลี่ยน state
Entity(entity).state:set(
'garage:locked',
locked == true,
true
)
end)
ตัวอย่างนี้แสดงแนวคิดให้ Server Set Replicated Entity State ส่วน Validation จริงต้องออกแบบตามระบบ Garage ของ Server
ตัวอย่าง Player State
Server:
RegisterCommand('duty', function(source)
if source == 0 then
return
end
local current = Player(source).state.duty == true
Player(source).state.duty = not current
end, false)
Player State เป็น State Type ที่ Cfx.re รองรับโดยตรง.
ตัวอย่าง GlobalState
Server:
GlobalState.serverEventActive = true
Client:
if GlobalState.serverEventActive then
print('Server event is active')
end
Global State ถูกกำหนดจาก Server และ Client สามารถอ่านค่าได้.
ตัวอย่าง Granular State Keys
หลีกเลี่ยง:
Entity(vehicle).state.vehicleData = {
fuel = 80,
locked = true,
engine = true
}
ถ้า Resource ต้องอ่าน/เปลี่ยน Sub-state บ่อย สามารถออกแบบเป็น:
local state = Entity(vehicle).state
state['vehicle:fuel'] = 80
state['vehicle:locked'] = true
state['vehicle:engine'] = true
แนวทาง Granular Keys สอดคล้องกับคำแนะนำ Shallow Limitations ของ Cfx.re.
FiveM State Bag กับ TriggerClientEvent อันไหนดีกว่า
ไม่มีคำตอบว่าอันหนึ่งดีกว่าทุกกรณี
ใช้:
TriggerClientEvent
เมื่อคุณต้องการส่ง Action/Event
ใช้:
State Bag
เมื่อคุณต้องการ Sync State
ตัวอย่าง:
“เปิด Notification ตอนนี้”
→ Event
“รถคันนี้ล็อกอยู่”
→ State
นี่ช่วยให้ Architecture อ่านง่ายและลด Network Logic ที่ซ้ำซ้อน
FiveM State Bag กับ GlobalState ต่างกันอย่างไร
GlobalState เป็น State Bag ประเภท Global ที่ Server เป็นผู้กำหนดและ Client อ่านได้ ส่วน Entity/Player State ถูกผูกกับ Entity หรือ Player เฉพาะราย.
ใช้ GlobalState เมื่อ State เป็นค่าร่วมของ Server ทั้งหมด
FiveM Player State ไม่ Sync แก้อย่างไร
ตรวจก่อนว่า State ถูกตั้งจาก Client หรือ Server
Cfx.re ระบุว่า Client-set State ไม่ Replicate โดย Default แต่ Server-set State Replicate โดย Default.
ถ้าต้องการ Client Replication ต้องใช้ state:set() ตาม Policy และต้องตรวจด้วยว่า Server เปิด Strict Mode หรือไม่.
FiveM Entity State ไม่ Sync แก้อย่างไร
ตรวจ:
Entity Networked?
↓
ใครเป็น Owner?
↓
ใคร Set State?
↓
Replicated หรือไม่?
↓
Strict Mode?
↓
Entity ยังอยู่ใน Scope?
State Bag Policy ปกติอนุญาตให้ Server และ Entity Owner เขียน Entity State แต่ Strict Mode สามารถเปลี่ยนให้เฉพาะ Server เป็นผู้แก้ Replicated Entity State ได้.
FiveM AddStateBagChangeHandler ใช้เมื่อไหร่
ใช้เมื่อ Resource ต้อง ตอบสนองทันทีเมื่อ State Key เปลี่ยน
เช่น:
vehicle:locked เปลี่ยน
↓
Update Door Lock
player:duty เปลี่ยน
↓
Update UI
global:event เปลี่ยน
↓
เปิด/ปิด Feature
Cfx.re ระบุว่า Change Handler ใช้ติดตาม State Bag Changes โดยตรง.
FAQ FiveM State Bags
FiveM State Bags คืออะไร
เป็น Key/Value State ที่ผูกกับ Entity, Player หรือ Global Server State และสามารถถูก Replicate ผ่านระบบ State Awareness ของ FiveM.
State Bags ใช้แทน TriggerClientEvent ได้ไหม
ใช้แทนได้เฉพาะบาง Use Case โดย State Bags เหมาะกับ State ส่วน Network Events เหมาะกับ Actions/Requests
Entity State ตั้งจาก Client ได้ไหม
Policy ปกติอนุญาต Entity Owner และ Server เขียน State ได้ แต่ Client-set State ไม่ Replicate โดย Default และ Strict Mode สามารถจำกัดให้เฉพาะ Server แก้ Replicated State ได้.
GlobalState ใครแก้ได้
Cfx.re ระบุว่า Global State เป็น Server-set และ Client-read.
State Bag Nested Table ทำไมไม่ Sync
Cfx.re ระบุว่า State Bag มี Shallow Limitations และการแก้ Nested Value เช่น state.x.y = value จะไม่ Replicate ตามที่คาด ควรใช้ Direct/Granular Key.
state:set ตัวสุดท้ายคืออะไร
เป็นตัวกำหนด Replication ของ State Set นั้น เช่น true เพื่อ Replicate หรือ false เพื่อเก็บ Local ตาม Context.
sv_stateBagStrictMode คืออะไร
เป็น Server ConVar ที่เมื่อเปิด true จะจำกัดให้เฉพาะ Server สามารถแก้ State ของ Networked Entities และ Player State ผ่าน Network ได้.
State Bags ใช้กับ OneSync ไหม
ใช่ในบริบทของ State Awareness/Entity Networking และ OneSync Documentation แนะนำ State Bags สำหรับ Attributes ของ Entities และ Scoped State.
ประเด็นสำคัญ
FiveM State Bags เป็นระบบสำหรับเก็บและ Synchronize Runtime State ผ่าน Key/Value โดยแบ่งการใช้งานหลักเป็น Entity State, Player State และ GlobalState และ Cfx.re ระบุว่า State จาก Server จะ Replicate โดย Default ขณะที่ State จาก Client จะไม่ Replicate โดย Default เว้นแต่กำหนดผ่าน state:set().
จุดที่ Developer ต้องระวังมากคือ Shallow Limitations เพราะการแก้ Nested Value เช่น state.x.y = value จะไม่ Replicate และการอ่าน Nested State ซ้ำสามารถทำให้เกิดการ Deserialize ซ้ำ Cfx.re จึงแนะนำให้ใช้ Keys แบบ Granular เช่น vehicle:fuel และ vehicle:locked.
เมื่อ State เปลี่ยนและ Resource ต้องตอบสนอง สามารถใช้ AddStateBagChangeHandler แทนการ Loop ตรวจค่าอย่างต่อเนื่อง และ OneSync Documentation ยังแนะนำ State Bags แทน Scope Events บางประเภทที่มี Scaling Performance Costs.
สำหรับ Server ที่ต้องการควบคุม State แบบ Server-authoritative มากขึ้น ปัจจุบัน Cfx.re มี sv_stateBagStrictMode; เมื่อเปิด true จะทำให้เฉพาะ Server สามารถแก้ Replicated State ของ Networked Entity และ Player State ได้.
สำหรับผู้อ่าน comsiam ให้จำสูตร “Event = เหตุการณ์, State Bag = สถานะ” และ comsiam แนะนำให้ใช้ State Keys ขนาดเล็กและชัดเจน ให้ Server เป็นผู้ตัดสิน State สำคัญ และใช้ Change Handler แทน Loop ทุก Tick เมื่อ Resource ต้องตอบสนองเฉพาะตอน State เปลี่ยน
Comments
Post a Comment