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 แก้อย่างไร

ตรวจตามลำดับ:

  1. State ถูก Set ฝั่งไหน

  2. Entity Networked หรือไม่

  3. ใครเป็น Entity Owner

  4. ใช้ .state.key = value หรือ .state:set()

  5. Replicated Parameter เป็น true หรือไม่

  6. เปิด sv_stateBagStrictMode หรือไม่

  7. Client/Server อยู่ Scope ที่เหมาะสมหรือไม่

  8. 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

ตรวจว่า:

  1. รู้ว่า State เป็น Entity/Player/Global

  2. State Key ตั้งชื่อชัดเจน

  3. ไม่เก็บ Secret ใน Replicated State

  4. Server เป็น Authority สำหรับข้อมูลสำคัญ

  5. เข้าใจ Default Replication

  6. เข้าใจ state:set()

  7. เข้าใจ Parameter Replicated

  8. ไม่แก้ Nested Table โดยตรง

  9. ใช้ Granular Keys

  10. ไม่อ่าน Nested State ซ้ำโดยไม่จำเป็น

  11. ใช้ Change Handler เมื่อเหมาะสม

  12. ไม่ Poll ทุก Tick หากไม่จำเป็น

  13. ตรวจ Entity Ownership

  14. ตรวจ Scope

  15. ตรวจ Strict Mode

  16. ใช้ Network Events สำหรับ Actions

  17. ใช้ State Bags สำหรับ State

  18. ไม่ใช้เป็น Database

  19. ทดสอบผู้เล่นหลายคน

  20. ดู Client/Server Console เมื่อ State ไม่ Sync

ตาราง State Bag ที่ควรรู้

ประเภทตัวอย่างจุดประสงค์
Entity StateEntity(vehicle).stateState ของ Entity
Player StatePlayer(source).stateState ของ Player
Local Player StateLocalPlayer.statePlayer State ฝั่ง Client
Global StateGlobalStateState ระดับ Server
state:set()Set พร้อมกำหนด Replicationควบคุม Local/Replicated
Change HandlerAddStateBagChangeHandlerฟัง State Change
Strict Modesv_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

Popular posts from this blog

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

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

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