AI Core
Dokumentacja APILib: klient

Punkty interakcji

Points - każde miejsce, z którego korzysta gracz (lady, sklepy, drzwi, NPC, bankomaty, bagażniki pojazdów), jako prompt albo opcja targetu, z pedami, blipami i punktami budowanymi z rekordów panelu.

Punkt to każde miejsce, z którego korzysta gracz: lada sklepu, drzwi, NPC, miejsce zwrotu, każdy bankomat, bagażnik każdego auta. Opisujesz go raz (gdzie, jaki tekst, co się dzieje), a lib rysuje go tak, jak wybrał właściciel serwera.

Prompt albo target

Właściciel wybiera styl interakcji w panelu administratora ai-core (Interaction [Interakcja]). W obu przypadkach działa to samo onPressed, więc twojego skryptu nie obchodzi, który jest włączony.

StylCo widzi gracz
PromptRamka "naciśnij E" po prawej stronie ekranu, gdy gracz stoi w promieniu punktu. Klawisz to jeden klawisz do przypisania w ai-lib (domyślnie E), więc nic nie odpytuje klawiszy co klatkę.
TargetOpcja w oku targetu na miejscu, NPC, obiekcie albo pojeździe. Wymaga, żeby działał jeden ze skryptów targetu, dla których lib ma adapter. Gdy działa kilka, wygrywa pierwszy w tej kolejności: ai-target, tgiann-radialmenu-target, tgiann-target, sleepless_interact, ox_target, qb-target, interact.

Gdy właściciel wybrał target, ale nie działa żaden skrypt targetu, każdy punkt jest promptem. Punkt może nadpisać wybór właściciela: promptOnly zostawia prompt (rzeczy robione z pojazdu: dystrybutory, myjnie), preferTarget używa opcji targetu zawsze, gdy działa skrypt targetu (siedzenia). Gdy skrypt targetu startuje albo się zatrzymuje albo właściciel zmienia styl, każdy punkt przechodzi sam.

Naraz działa tylko jedna akcja punktu twojego zasobu. Gdy onPressed zwraca promise, pozostałe punkty twojego zasobu ignorują naciśnięcia, aż się zakończy, więc nigdy nie potrzebujesz własnej flagi busy. W chwili naciśnięcia gracz musi też przejść canShow.

new Points

Tworzy grupę punktów. Zrób jedną grupę na funkcję na górze pliku i dodawaj do niej punkty.

Strona: Klient · Czeka: nie

Sygnatura
new Points()
Lua
local points = aiLib.Points.new()

Zwracana wartość

Grupa Points z metodami poniżej.

Przykład

import { Points } from "@aicore-fivem/lib/client";

const points = new Points();

points.add

Dodaje punkt w miejscu albo zastępuje punkt o tym samym id. Punkt może nieść własnego NPC (ped) i blip na mapie (blip).

Strona: Klient · Czeka: nie

Sygnatura
points.add(id: string, options: PointOptions): void
Lua
points:add(id, options)

Parametry

Prop

Type

PointOptions

Prop

Type

PointPed

Pole ped przyjmuje opcje LocalPed z wyjątkiem onSpawn i onDespawn (używa ich punkt):

Prop

Type

PointBlip

Pole blip przyjmuje opcje blipa; coords domyślnie to punkt:

Prop

Type

PromptAnchor

Co zwraca funkcja world (PromptAnchor), jedno z:

Prop

Type

Zwracana wartość

void.

Przykład

resource/client/index.ts
import { callAction, createLocale, hasJob, onMembershipChange, Points } from "@aicore-fivem/lib/client";

const Locale = createLocale<typeof import("../../locales/en.json")>();
const points = new Points();

// Lada sklepu ze sprzedawcą i blipem na mapie.
points.add("shop", {
  coords: { x: 25.7, y: -1347.3, z: 29.5 },
  label: Locale("OPEN_SHOP"),
  icon: "basket-shopping",
  ped: { model: "mp_m_shopkeep_01", coords: { x: 24.5, y: -1346.6, z: 29.5, heading: 270 } },
  blip: { sprite: 52, color: 2, label: Locale("SHOP") },
  onPressed: () => callAction("myshop:open", [], { fallback: "SHOP_FAILED" }),
});

// Schowek, który może otworzyć tylko policja; tekst podąża za stanem.
let locked = true;
points.add("evidence", {
  coords: { x: 474.9, y: -996.4, z: 26.3 },
  label: () => (locked ? Locale("UNLOCK") : Locale("LOCK")),
  icon: "box-archive",
  canShow: () => hasJob(["police"], 2),
  onPressed: async () => {
    const reply = await callAction("myscript:toggle", [], { fallback: "TOGGLE_FAILED" });
    if (reply) locked = !locked;
    points.refresh("evidence");
  },
});

// canShow czyta pracę: sprawdź ponownie, gdy zmienią się prace, służba albo gangi.
onMembershipChange(() => points.refresh());

canShow decyduje tylko o tym, co widzi gracz. Serwer musi sprawdzić ponownie (praca, odległość, zapas) we własnym handlerze. Oszust może wywołać twoje zdarzenie serwera bez żadnego punktu.

points.addModel

Dodaje punkt na każdym obiekcie świata o danych modelach (bankomaty, automaty, kontenery, krzesła) albo zastępuje punkt o tym samym id. W trybie targetu to opcja targetu na tych modelach; w trybie promptu prompt pokazuje się przy najbliższym z nich. Skanowanie w poszukiwaniu najbliższego obiektu działa raz w ai-lib za wszystkie zasoby, dwa razy na sekundę, i wstrzymuje się, gdy gracz stoi w miejscu.

Strona: Klient · Czeka: nie

Sygnatura
points.addModel(id: string, options: ModelPointOptions): void
Lua
points:addModel(id, options)

Parametry

Prop

Type

ModelPointOptions

Prop

Type

Zwracana wartość

void.

Przykład

import { callAction, createLocale, Points } from "@aicore-fivem/lib/client";

const Locale = createLocale<typeof import("../../locales/en.json")>();
const points = new Points();

points.addModel("atm", {
  models: ["prop_atm_01", "prop_atm_02", "prop_atm_03", "prop_fleeca_atm"],
  label: Locale("USE_ATM"),
  icon: "credit-card",
  onPressed: (atm) => callAction("mybank:atm", [NetworkGetNetworkIdFromEntity(atm)], { fallback: "ATM_FAILED" }),
});

Dwa stany jednego obiektu (przywiąż i odwiąż łódź) to dwa punkty modeli z przeciwnym canShow, a nie jedna funkcja etykiety. Punkt z więcej niż 6 modelami znajduje swoje obiekty przez indeks puli obiektów, więc setki modeli kosztują tyle samo co kilka.

points.addVehicle

Dodaje punkt na każdym pojeździe sieciowym (bagażnik, maska, pchanie, naprawa) albo zastępuje punkt o tym samym id. W trybie targetu to globalna opcja pojazdów skryptu targetu; w trybie promptu prompt pokazuje się przy najbliższym pojeździe sieciowym w promieniu radius.

Strona: Klient · Czeka: nie

Sygnatura
points.addVehicle(id: string, options: VehiclePointOptions): void
Lua
points:addVehicle(id, options)

Parametry

Prop

Type

Zwracana wartość

void.

Przykład

import { cache, createLocale, Points } from "@aicore-fivem/lib/client";

const Locale = createLocale<typeof import("../../locales/en.json")>();
const points = new Points();

points.addVehicle("trunk", {
  label: Locale("OPEN_TRUNK"),
  icon: "box-open",
  radius: 2.5,
  canShow: (vehicle) => vehicle !== 0 && cache.vehicle === false && GetVehicleDoorLockStatus(vehicle) < 2,
  onPressed: (vehicle) => SetVehicleDoorOpen(vehicle, 5, false, false),
});

points.remove

Usuwa jeden punkt z jego promptem, opcją targetu, NPC i blipem. Działa dla punktów zrobionych przez add, addModel i addVehicle. Nieznane id nic nie robi.

Strona: Klient · Czeka: nie

Sygnatura
points.remove(id: string): void
Lua
points:remove(id)

Parametry

Prop

Type

Zwracana wartość

void.

Przykład

points.remove("shop");

points.clear

Usuwa każdy punkt grupy.

Strona: Klient · Czeka: nie

Sygnatura
points.clear(): void
Lua
points:clear()

Zwracana wartość

void.

Przykład

onServerEvent("myscript:jobEnded", () => points.clear());

Nigdy nie przebudowuj punktów panelu przez clear() + dodanie wszystkiego przy każdej zmianie panelu: przy tysiącach rekordów jedna edycja przebudowałaby wszystkie na każdym kliencie. Użyj RecordObjects: edycja przebudowuje tylko własny rekord.

points.refresh

Ponownie czyta canShow i etykiety-funkcje. Wywołaj ją, gdy zmieniło się coś, co czytają: praca, służba, pojazd, stan wysłany przez serwer. Prompty aktualizują się od razu; opcje targetu czytają canShow, gdy oko się otwiera, a zmieniona etykieta jest zakładana ponownie.

Strona: Klient · Czeka: nie

Sygnatura
points.refresh(id?: string): void
Lua
points:refresh() -- każdy punkt grupy

Parametry

Prop

Type

Zwracana wartość

void.

Przykład

import { EntityState, onCache, onMembershipChange, Points, stateBoolean } from "@aicore-fivem/lib/client";

const points = new Points();
const robbed = new EntityState("robbed", stateBoolean);

onCache("vehicle", () => points.refresh());
onMembershipChange(() => points.refresh());
// Zmieniła się jedna kasa: odśwież tylko jej punkt.
robbed.onChange((netId) => points.refresh(`register:${netId}`));

Wewnątrz surowego AddStateBagChangeHandler nowej wartości nie da się jeszcze odczytać: wywołaj tam refresh w setTimeout(..., 0). Klasy stanu liba (EntityState.onChange) już dają ci nową wartość.

points.isInside

Czy gracz stoi teraz w promieniu punktu (punkty zrobione przez add).

Strona: Klient · Czeka: nie

Sygnatura
points.isInside(id: string): boolean

Brak odpowiednika w Lua.

Parametry

Prop

Type

Zwracana wartość

boolean: true, dopóki gracz jest wewnątrz; false na zewnątrz albo dla nieznanego id lub punktu modelu.

Przykład

if (points.isInside("garage")) notify(Locale("PARK_HERE"), "info");

points.restyle

Przestawia każdy punkt grupy na bieżący styl interakcji. Lib wywołuje to sam, gdy właściciel zmieni styl albo skrypt targetu wystartuje lub się zatrzyma; nigdy tego nie potrzebujesz.

Strona: Klient · Czeka: nie

Sygnatura
points.restyle(): void

Brak odpowiednika w Lua (Lua też sam zmienia styl).

Zwracana wartość

void.

Punkty z rekordów panelu

Większość punktów pochodzi z pliku rekordów panelu administratora twojego skryptu (sklepy, garaże, punkty wypożyczeń). Odwzoruj plik na kliencie przez AdminWorld, potem zbuduj punkty każdego rekordu przez RecordObjects: edytowany rekord przebudowuje tylko własne punkty, usunięty je usuwa.

new RecordObjects

Utrzymuje obiekty świata z pliku rekordów (punkty, blipy, pedy, strefy) zgodne z plikiem, po jednym rekordzie. build(key, record) tworzy obiekty jednego rekordu i zwraca, jak je usunąć. Buduje każdy rekord w konstruktorze.

Strona: Klient i serwer (z @aicore-fivem/lib/shared) · Czeka: nie

Sygnatura
new RecordObjects<T>(
  source: RecordSource,
  file: string,
  records: RecordReader<T> | ReadonlyMap<string, T>,
  build: (key: string, record: T) => (() => void) | void,
)

Brak odpowiednika w Lua.

Parametry

Prop

Type

Składowe

Prop

Type

Przykład

resource/client/index.ts
import { AdminWorld, callAction, createLocale, Points } from "@aicore-fivem/lib/client";
import { readVec3, RecordObjects, str } from "@aicore-fivem/lib/shared";

const Locale = createLocale<typeof import("../../locales/en.json")>();
const world = new AdminWorld(["settings", "shops"]);
const points = new Points();

interface Shop { label: string; coords: { x: number; y: number; z: number } }
const readShop = (_key: string, raw: Record<string, unknown>): Shop | null => {
  const coords = readVec3(raw.coords);
  return coords ? { label: str(raw.label, "Shop"), coords } : null;
};

const shops = new RecordObjects(world, "shops", readShop, (id, shop) => {
  points.add(id, {
    coords: shop.coords,
    label: Locale("OPEN_SHOP", shop.label),
    onPressed: () => callAction("myshop:open", [id], { fallback: "SHOP_FAILED" }),
  });
  return () => points.remove(id);
});

// Zmieniło się ustawienie, które czyta każdy sklep: przebuduj je wszystkie.
world.onChange("settings", () => shops.rebuildAll());

RecordObjects buduje w konstruktorze. Utwórz go po wszystkim, co czyta build, a wewnątrz build używaj argumentu record: pole klasy, które trzyma RecordObjects, podczas tego pierwszego budowania nie jest jeszcze przypisane.

new AdminWorld

Kliencka kopia światowych plików panelu twojego skryptu (plików, których schemat mówi sync: "all", zobacz Panel administratora). Czyta kopię zapisaną przez FiveM w pamięci podręcznej przy starcie, raz pyta serwer o rekordy zmienione od tego czasu, potem śledzi zmiany na żywo. Nigdy nie odpytuje.

Strona: Klient · Czeka: nie (promise ready mówi, kiedy przyszły zmiany od startu)

Sygnatura
new AdminWorld(files: string[])

Brak odpowiednika w Lua.

Parametry

Prop

Type

Składowe

Prop

Type

Przykład

import { AdminWorld } from "@aicore-fivem/lib/client";
import { num, record } from "@aicore-fivem/lib/shared";

const world = new AdminWorld(["settings"]);
const settings = world.view("settings", (raw) => ({
  radius: num(record(raw).radius, 2),
}));

world.onChange("settings", () => console.log("new radius", settings.value.radius));

Na tej stronie