Действия и ввод от клиента
fail, isActionOk, replyError и строгие функции чтения readInt, readFinite, readId, readText, readVec3, readVec4, oneArg, asArgs, isRecord.
Всё, что отправляет клиент, читер может подделать: отрицательную сумму, дробь там, где вы ждёте целое число, строку на 10 МБ, объект вместо числа. Строгие функции чтения на этой странице превращают одно сырое значение в проверенное значение или в null, чтобы отказать. Они никогда не заменяют неверное значение значением по умолчанию (это делают функции чтения данных панели для файлов, которые редактирует владелец сервера).
Каждое серверное действие отвечает ActionResult: { ok: true } или отказом с языковым ключом.
import { fail, isActionOk, replyError, readInt, readFinite, readId, readText, readVec3, readVec4, oneArg, asArgs, isRecord } from "@aicore-fivem/lib/shared";Где используются функции чтения: опция args у onClientCallback и onClientEvent (см. Ввод от клиента). Парсер получает сырые аргументы массивом и возвращает проверенные массивом или null, чтобы отклонить вызов ещё до запуска вашего обработчика.
Результаты действий
fail
Создаёт отказ: { ok: false, error }. Верните его из обработчика действия; клиентский callAction покажет переведённый текст error как уведомление об ошибке.
Сторона: Клиент, сервер и NUI · Ждёт: нет
fail(error: string): { ok: false; error: string }return aiLib.fail('NOT_ENOUGH_MONEY') -- { ok = false, error = 'NOT_ENOUGH_MONEY' }Параметры
Prop
Type
Возвращает
{ ok: false, error: string }, что подходит к любому ActionResult.
Пример
import { onClientCallback, resourceExport } from "@aicore-fivem/lib/server";
import { fail, oneArg, readInt, type ActionResult } from "@aicore-fivem/lib/shared";
const core = resourceExport("ai-core");
onClientCallback(
"my-shop:buyWater",
{ args: oneArg((v) => readInt(v, 1, 10)), lock: true },
(source, count): ActionResult => {
if (!core.CanCarryItem(source, "water", count)) return fail("NO_SPACE");
if (!core.RemoveMoney(source, "cash", count * 5, "Water")) return fail("NOT_ENOUGH_MONEY");
core.AddItem(source, "water", count);
return { ok: true };
},
);На клиенте callAction("my-shop:buyWater", [2], { fallback: "BUY_FAILED" }) (в Lua aiLib.callAction) показывает отказ за вас. См. Связь с сервером.
isActionOk
Проверяет, является ли ответ успешным ActionResult (ok === true). Используйте, когда читаете ответ вручную, а не через callAction.
Сторона: Клиент, сервер и NUI · Ждёт: нет
isActionOk(reply: unknown): reply is { ok: true } & Record<string, unknown>Lua: аналога нет; проверьте type(reply) == 'table' and reply.ok == true.
Параметры
Prop
Type
Возвращает
true, если reply является объектом с ok: true. Дополнительные поля не проверяются: разбирайте те, которые читаете.
Пример
import { triggerServerCallback } from "@aicore-fivem/lib/client";
import { isActionOk, readId } from "@aicore-fivem/lib/shared";
/** Asks the server to create a garage; answers its new id, or null. */
async function createGarage(name: string): Promise<number | null> {
const reply = await triggerServerCallback("my-garage:create", [name]).catch(() => null);
if (!isActionOk(reply)) return null;
return readId(reply.id); // дополнительное поле: проверяйте его, как любой другой ввод
}replyError
Языковой ключ отклонённого ответа: его error или fallback, если ответа нет или он искажён. null, если ответ успешный.
Сторона: Клиент, сервер и NUI · Ждёт: нет
replyError(reply: unknown, fallback: string): string | nullLua: аналога нет.
Параметры
Prop
Type
Возвращает
null для успешного ответа. Иначе error ответа, если это непустая строка, иначе fallback.
Пример
import { triggerServerCallback, notify, loadLocaleTexts } from "@aicore-fivem/lib/client";
import { replyError } from "@aicore-fivem/lib/shared";
const texts = loadLocaleTexts();
async function buyWater(): Promise<boolean> {
const reply = await triggerServerCallback("my-shop:buy", ["water"]).catch(() => null);
const error = replyError(reply, "BUY_FAILED");
if (error !== null) notify(texts[error] ?? error, "error");
return error === null;
}Строгие функции чтения
readFinite
Конечное число, иначе null. NaN, Infinity, текст и всё остальное отклоняются.
Сторона: Клиент, сервер и NUI · Ждёт: нет
readFinite(value: unknown): number | nullLua: аналога нет; проверьте type(value) == 'number' and value == value and value ~= math.huge and value ~= -math.huge.
Параметры
Prop
Type
Возвращает
Число или null.
Пример
import { readFinite } from "@aicore-fivem/lib/shared";
readFinite(12.5); // 12.5
readFinite(NaN); // null
readFinite("12"); // nullreadInt
Целое число от min до max (оба включительно), иначе null. Дроби, NaN, Infinity, текст и значения вне диапазона отклоняются. Используйте для количеств, сумм, слотов, индексов.
Сторона: Клиент, сервер и NUI · Ждёт: нет
readInt(value: unknown, min: number, max: number): number | nullLua: аналога нет; проверьте math.type(value) == 'integer' and value >= min and value <= max.
Параметры
Prop
Type
Возвращает
Число или null.
Пример
import { onClientCallback, resourceExport } from "@aicore-fivem/lib/server";
import { fail, readInt, readText } from "@aicore-fivem/lib/shared";
const core = resourceExport("ai-core");
const prices = new Map<string, number>([["water", 5], ["bread", 3]]);
onClientCallback(
"my-shop:buy",
{
args: ([rawItem, rawCount]) => {
const item = readText(rawItem, 64);
const count = readInt(rawCount, 1, 50);
return item !== null && count !== null ? [item, count] : null;
},
lock: true,
},
(source, item, count) => {
const price = prices.get(item); // только предметы, которые продаёт этот магазин
if (price === undefined) return fail("UNKNOWN_ITEM");
if (!core.CanCarryItem(source, item, count)) return fail("NO_SPACE");
if (!core.RemoveMoney(source, "cash", price * count, "Shop")) return fail("NOT_ENOUGH_MONEY");
core.AddItem(source, item, count);
return { ok: true };
},
);readId
Положительное 32-битное целое число (от 1 до 2 147 483 647), иначе null. Используйте для id записей, токенов и сетевых id, которые отправляет клиент.
Сторона: Клиент, сервер и NUI · Ждёт: нет
readId(value: unknown): number | nullLua: аналога нет; проверьте math.type(value) == 'integer' and value > 0 and value <= 2147483647.
Параметры
Prop
Type
Возвращает
Id или null.
Пример
import { onClientCallback, vehicleFromNet } from "@aicore-fivem/lib/server";
import { oneArg, readId, fail } from "@aicore-fivem/lib/shared";
onClientCallback("my-tow:attach", { args: oneArg(readId) }, (source, netId) => {
const vehicle = vehicleFromNet(netId);
if (vehicle === 0) return fail("NO_VEHICLE");
return { ok: true };
});Верный id ещё не означает верную цель. Всегда проверяйте, что запись или сущность существует, что игрок может её использовать и что он рядом с ней.
readText
Обрезанная по краям непустая строка, урезанная до max символов, иначе null. Используйте для имён, названий предметов, заметок, текста поиска.
Сторона: Клиент, сервер и NUI · Ждёт: нет
readText(value: unknown, max: number): string | nullLua: аналога нет; проверьте type(value) == 'string', затем обрежьте пробелы и укоротите строку (value:sub(1, max)).
Параметры
Prop
Type
Возвращает
Обрезанный текст (не более max символов) или null, если это не строка или она пуста после обрезки.
Пример
import { readText } from "@aicore-fivem/lib/shared";
readText(" Hello ", 64); // "Hello"
readText(" ", 64); // null
readText(42, 64); // nullreadVec3
Точка из ввода клиента или экспорта, все координаты конечные, иначе null. Принимает объект { x, y, z } и вектор Lua, который приходит в TypeScript как массив [x, y, z].
Сторона: Клиент, сервер и NUI · Ждёт: нет
readVec3(value: unknown): { x: number; y: number; z: number } | nullLua: аналога нет; код на Lua читает value.x, value.y, value.z (работает для векторов и таблиц).
Параметры
Prop
Type
Возвращает
Новый объект Vec3 или null.
Пример
import { registerExport } from "@aicore-fivem/lib/server";
import { readVec3, type Vec3 } from "@aicore-fivem/lib/shared";
const markers: Vec3[] = [];
// Работает для exports["my-markers"].AddMarker(vector3(1, 2, 3)) из Lua и AddMarker({ x: 1, y: 2, z: 3 }) из TypeScript.
registerExport("AddMarker", (raw: unknown) => {
const point = readVec3(raw);
if (!point) return false;
markers.push(point);
return true;
});readVec4
Точка с направлением, иначе null. Принимает { x, y, z, heading }, { x, y, z, w } и vector4 из Lua ([x, y, z, w]). Отсутствующее направление читается как 0.
Сторона: Клиент, сервер и NUI · Ждёт: нет
readVec4(value: unknown): { x: number; y: number; z: number; heading: number } | nullLua: аналога нет.
Параметры
Prop
Type
Возвращает
Новый объект Vec4 (heading 0, если направление не задано) или null, если координата или заданное направление не является конечным числом.
Пример
import { readVec4 } from "@aicore-fivem/lib/shared";
readVec4({ x: 1, y: 2, z: 3, w: 90 }); // { x: 1, y: 2, z: 3, heading: 90 }
readVec4([1, 2, 3]); // { x: 1, y: 2, z: 3, heading: 0 }
readVec4({ x: 1, y: 2 }); // nulloneArg
Превращает функцию чтения в парсер args для колбэка или события, которое принимает ровно одно значение: { args: oneArg(readId) }.
Сторона: Клиент, сервер и NUI · Ждёт: нет
oneArg<T>(read: (value: unknown) => T | null): (args: unknown[]) => [T] | nullLua: аналога нет.
Параметры
Prop
Type
Возвращает
Парсер, который возвращает [value] или null (отклоняет вызов), если read вернула null.
Пример
import { onClientCallback } from "@aicore-fivem/lib/server";
import { oneArg, readText } from "@aicore-fivem/lib/shared";
const notes = new Map<number, string>();
onClientCallback("my-notes:save", { args: oneArg((v) => readText(v, 500)) }, (source, text) => {
notes.set(source, text);
return { ok: true };
});asArgs
Оборачивает одно уже разобранное значение как результат args: [value] или null, если значение null. Используйте, когда ваша собственная функция проверки возвращает значение или null.
Сторона: Клиент, сервер и NUI · Ждёт: нет
asArgs<T>(value: T | null): [T] | nullLua: аналога нет.
Параметры
Prop
Type
Возвращает
[value] или null.
Пример
import { onClientCallback } from "@aicore-fivem/lib/server";
import { asArgs, toVehicleSetup, type VehicleSetup } from "@aicore-fivem/lib/shared";
const previews = new Map<number, VehicleSetup>();
onClientCallback("my-shop:preview", { args: ([raw]) => asArgs(toVehicleSetup(raw)) }, (source, setup) => {
previews.set(source, setup);
return { ok: true };
});isRecord
Проверяет, что значение является простым объектом (не null и не массивом).
Сторона: Клиент, сервер и NUI · Ждёт: нет
isRecord(value: unknown): value is Record<string, unknown>Lua: аналога нет; проверьте type(value) == 'table'.
Параметры
Prop
Type
Возвращает
true для объекта вида { a: 1 }. false для null, массивов, чисел, строк.
Пример
import { isRecord, readText } from "@aicore-fivem/lib/shared";
function readNote(raw: unknown): { title: string } | null {
if (!isRecord(raw)) return null;
const title = readText(raw.title, 80);
return title === null ? null : { title };
}