Torebki stanu w FiveM: Entity(entity).state, GlobalState i handlery

Jak działają torebki stanu w FiveM: Entity(entity).state, Player(source).state, LocalPlayer.state, GlobalState, :set, handlery zmian i kiedy preferować je zamiast zdarzeń

Chcesz udostępnić małą część danych między serwerem a każdym klientem, na przykład że pojazd jest zablokowany, że gracz jest puta do kajdanek, lub bieżącą pogodę, a ciągle piszesz zdarzenia, które uruchamiają się przy każdej zmianie i tracą synchronizację dla graczy, którzy dołączają później. Torebki stanu są wbudowaną odpowiedzią.

Ten artykuł obejmuje typy torebek stanu, jak je pisać i czytać, jak reagować na zmiany i kiedy zdarzenie jest wciąż lepszym wyborem.

Co to jest torebka stanu

Torebka stanu to magazyn tabelaryczny kluczy i wartości dołączony do czegoś. Runtime synchronizuje go dla ciebie, łącznie z graczami, którzy połączą się po ustawieniu wartości. FiveM daje ci trzy rodzaje:

Torebka Czytaj i pisz za pomocą Istnieje na
Encja Entity(entity).state Encji (ped, pojazd, obiekt)
Gracz Player(source).state na serwerze, LocalPlayer.state na kliencie Graczu
Serwer GlobalState Całym serwerze

We wszystkich z nich czytasz wartość jak normalne pole:

lua
local locked = Entity(vehicle).state.locked

Pisanie z serwera

Na serwerze ustawienie wartości replikuje ją do klientów, którzy widzą tę torebkę:

lua
-- server
local veh = CreateVehicle(`adder`, 215.0, -810.0, 30.7, 90.0, true, true)
Entity(veh).state.locked = true

Player(source).state.cuffed = true

GlobalState.weather = 'RAIN'

Możesz użyć stylu pola lub jawnego wywołania, które również pozwala wybrać, czy wartość jest replikowana:

lua
Entity(veh).state:set('locked', true, true)

:set(key, value, replicated) przyjmuje klucz, wartość i wartość logiczną. Z true wartość jest wysyłana na drugą stronę, z false pozostaje po stronie, która ją napisała.

Porada: wartości mogą być liczbami, stringami, wartościami logicznymi i tabelami. Tabela jest kopiowana podczas ustawiania, więc zmiana pola w tabeli, którą czytasz, nic nie robi. Ustaw całą tabelę ponownie, aby ją zaktualizować.

Pisanie z klienta

Klient może pisać do swojego własnego gracza i do encji, którymi steruje, ale zwykłe przypisanie pozostaje lokalne:

lua
-- client
LocalPlayer.state:set('inService', true, true)  -- replicated to the server
LocalPlayer.state.hasMask = true                -- local only

Serwer może przeczytać Player(source).state.inService potem. Traktuj to jako niezaufane: zmodyfikowany klient może napisać dowolną wartość. Użyj stanu napisanego przez klienta dla wygody, takiej jak flagi interfejsu, i trzymaj wszystko z zaletą dołączoną (pieniądze, praca, uprawnienia) na serwerze.

GlobalState jest odwrotnie: serwer go pisze, każdy klient go czyta, a klienci nie mogą go zmieniać dla innych.

lua
-- client
local weather = GlobalState.weather

Reagowanie na zmiany

Zamiast sondować wartość w pętli, zarejestruj handler, który działa, gdy zmieni się klucz. To główny powód, aby używać torebek stanu na kliencie:

lua
-- AddStateBagChangeHandler(keyFilter, bagFilter, handler)
AddStateBagChangeHandler('locked', nil, function(bagName, key, value, reserved, replicated)
    local entity = GetEntityFromStateBagName(bagName)
    if entity == 0 then return end

    SetVehicleDoorsLocked(entity, value and 2 or 1)
end)
  • keyFilter to klucz, na którym ci zależy, lub nil dla każdego klucza.
  • bagFilter ogranicza torbę, na przykład konkretną torbę gracza, lub nil dla wszystkich.
  • bagName wygląda jak entity:1234, player:5 lub global. GetEntityFromStateBagName zamienia torbę encji na handle, a GetPlayerFromStateBagName robi to samo dla torby gracza.

Na kliencie encja może jeszcze nie istnieć, gdy handler się uruchamia, na przykład dla pojazdu, który nadal przesyła. GetEntityFromStateBagName może w tym przypadku zwrócić 0, więc je sprawdź. Ponowne przeczytanie stanu, gdy encja przesyła, jest bezpiecznym nawykiem.

Ta sama funkcja istnieje na serwerze, gdzie jest przydatna do reagowania na pisanie przez klienta wartości replikowanej.

Torebki stanu lub zdarzenia

Użyj torebki stanu, gdy Użyj zdarzenia, gdy
Wartość opisuje aktualny stan czegoś (zablokowany, kajdanki, w służbie) Coś się stało raz (zakup, trafienie, wciśnięcie przycisku)
Gracze, którzy dołączą później, muszą zobaczyć wartość Tylko gracze obecni teraz muszą wiedzieć
Wielu graczy musi to czytać w dowolnym momencie Jeden gracz musi być coś poinformowany
W innym przypadku sondowałbyś w pętli Musisz przekazać wynik lub jednorazowy ładunek

Dobra reguła: zdarzenia są dla akcji, torebki stanu są dla stanu. Jeśli gracz dołączający w połowie musiałby być poinformowany o tym samym ponownie, to jest stan. Przeczytaj zdarzenia klient i serwer aby dowiedzieć się więcej.

Częste błędy

  • Używanie go do dużych lub szybko zmieniających się danych. Każda zmiana jest wysyłana przez sieć. Nie pisz pozycji do torebki stanu każdej ramki.
  • Ufanie zapisu klienta. Zweryfikuj wszystko, co klient ustawił, zanim będziesz na tym działać na serwerze.
  • Oczekiwanie, że handler uruchomi się przed istnieniem encji. Sprawdź handle i ponownie przeczytaj stan, gdy encja się pojawi.
  • Mutowanie tabeli w miejscu. Przeczytanie state.items, dodanie do niej i nieustaw ponownie nie zmienia nic.
  • Zapomnienie o resetowaniu. Stan na encji znika z encją, ale stan na graczu lub GlobalState pozostaje, aż go wyczyścisz, więc ustaw go na nil, gdy skończysz.
lua
Player(source).state.cuffed = nil

Lista kontrolna

Objaw Naprawa
Klient ustawia wartość, ale serwer jej nigdy nie widzi Użyj :set(key, value, true), aby była replikowana
Handler uruchamia się, ale handle encji to 0 Encja nie jest jeszcze przesyłana: sprawdź i przeczytaj stan ponownie później
Spóźnieni dołączy chybią wartość Użyj torebki stanu zamiast zdarzenia
Zmiana tabeli nie synchronizuje się Ustaw całą tabelę ponownie za pomocą :set
Nie można zmienić GlobalState z klienta Tylko serwer go pisze: wyślij zdarzenie i pozwól serwerowi to ustawić
Stara wartość pozostaje po zakończeniu pracy Ustaw klucz na nil

Szybkie odpowiedzi

Co to jest torebka stanu w FiveM?

Magazyn pary klucz-wartość dołączony do encji, gracza lub całego serwera. Wartości, które ustawisz, są synchronizowane między stronami przez grę, więc nie musisz uruchamiać zdarzenia dla każdej zmiany.

Czy klient może zmienić torebkę stanu i sprawić, że serwer to zobaczy?

Tylko jeśli wartość jest ustawiona z włączoną replikacją, na przykład LocalPlayer.state:set('key', value, true). Zwykłe przypisanie na kliencie pozostaje lokalne, a serwer nigdy nie powinien mu ufać w niczym, co ma znaczenie.

Czy torebki stanu potrzebują OneSync?

Torebki stanu encji zależą od OneSync, które obecne serwery domyślnie używają. Stan gracza i GlobalState są łatwiejszymi przypadkami, od których warto zacząć.

Skrypty bez tego problemu

Parrots as PetsCzternaście ptaków, które siedzą ci na ramieniu, latają z tobą i wracają na zawołanie.Zobacz skrypt →Advanced BoostingBoosting pojazdów z tabletu: kontrakty od klasy D do S+, ekipy i kolejka na żywo.Zobacz skrypt →Hookah SystemFajki wodne i meble lounge do rozstawienia, z ponad 50 smakami i efektami.Zobacz skrypt →

Czytaj dalej