Счета
Отправлять счета (штрафы, оплата услуг, счета от игроков), получать список открытых счетов игрока и оплачивать их через тот скрипт счетов, который работает, или через собственные счета ai-core.
Счета идут через ai-core, а не через собственные экспорты или события скрипта счетов. ai-core отправляет каждый счёт активному скрипту счетов: тому, что выбран в настройке панели Billing script, или первому запущенному. Если такого нет, счёт принимают собственные счета ai-core: игрок видит на экране список открытых счетов, а деньги перемещаются, когда он платит. Счёт никогда не пропадает впустую.
Счёт приходит от работы (платёж получает счёт bank этой работы: полицейские штрафы, оплата механику) или от игрока (платёж получает этот игрок).
Собственные счета ai-core вкратце: открытые счета хранятся по персонажам (в том числе офлайн), не более 20 открытых счетов на персонажа, а оплата списывает деньги с bank, затем с cash в одной транзакции с удалением счёта.
GetBillingSystem
Куда идут счета.
Сторона: сервер · Ожидание: нет · Библиотека: billing.provider()
GetBillingSystem(): string | nulllocal system = exports['ai-core']:GetBillingSystem() -- 'ai-core' или имя скриптаПараметры
Нет.
Возвращает
string | null: имя ресурса скрипта счетов или "ai-core" для собственных счетов ai-core. Поскольку собственные счета ai-core доступны всегда, на практике это не null.
Пример
import { resourceExport } from "@aicore-fivem/lib/server";
const core = resourceExport("ai-core");
/** Bills to offline characters only work with ai-core's own bills. */
export function canBillOffline(): boolean {
return core.GetBillingSystem() === "ai-core";
}SendBill
Отправляет игроку счёт.
Сторона: сервер · Ожидание: нет · Библиотека: billing.send
SendBill(bill: BillRequest): booleanlocal sent = exports['ai-core']:SendBill({ to = target, amount = 250, label = 'Speeding', from = source, job = 'police' })Параметры
Prop
Type
BillRequest
Prop
Type
См. BillRequest.
Возвращает
boolean: true, когда счёт отправлен. false, когда:
- счёт недопустим: указаны оба или ни одного из
to/toCitizenid, нетlabel,amountне целое число от 1 до 10 000 000, нет ниjob, ниfromилиfromсовпадает с получателем; fromуказан, но у него нет загруженного персонажа, илиjobне существует;- получатель офлайн, а счета идут в скрипт счетов (только собственные счета ai-core доходят до офлайн-персонажей);
- скрипт счетов отказал или у получателя уже 20 открытых счетов в собственных счетах ai-core.
Офлайн-счёт в собственных счетах ai-core отвечает true, как только он допустим; база данных всё ещё может его отклонить (неизвестный citizen id, 20 открытых счетов), и это записывается в лог.
Пример
import { onClientCallback, coordsOf, isNear, resourceExport } from "@aicore-fivem/lib/server";
import { fail, readId, readInt } from "@aicore-fivem/lib/shared";
import { Locale } from "common";
const core = resourceExport("ai-core");
// Офицер штрафует игрока перед собой; деньги получает счёт полиции.
onClientCallback(
"myscript:fine",
{
args: ([target, amount]) => {
const t = readId(target);
const a = readInt(amount, 1, 50_000);
return t === null || a === null ? null : [t, a];
},
},
(source, target, amount) => {
if (core.GetDutyJob(source) !== "police") return fail("NOT_POLICE");
if (!isNear(target, coordsOf(source), 3)) return fail("TOO_FAR");
const sent = core.SendBill({ to: target, amount, label: Locale("BILL_FINE"), from: source, job: "police" });
return sent ? { ok: true } : fail("BILL_FAILED");
},
);Никогда не забирайте деньги у цели сами как «принудительный счёт» (TransferMoney с её счёта): счёт - это выбор игрока, платить или нет.
GetUnpaidBills
Открытые (неоплаченные) счета игрока.
Сторона: сервер · Ожидание: нет (отвечает через done) · Библиотека: billing.unpaid(source) возвращает Promise
GetUnpaidBills(source: number, done: (bills: UnpaidBill[] | null) => void): voidexports['ai-core']:GetUnpaidBills(source, function(bills) end) -- список или nilПараметры
Prop
Type
Возвращает
Ничего. done получает по записи на каждый открытый счёт с id (id в скрипте счетов), label, amount (сколько ещё должен) и sender (название работы или имя игрока) (UnpaidBill) или null, когда у игрока нет загруженного персонажа или скрипт счетов не умеет перечислять счета. Если done не функция, вызов ничего не делает.
Пример
import { onClientCallback, resourceExport } from "@aicore-fivem/lib/server";
import { fail } from "@aicore-fivem/lib/shared";
import type { UnpaidBill } from "@aicore-fivem/shared";
const core = resourceExport("ai-core");
// Стойка в мэрии показывает, сколько игрок должен.
onClientCallback("myscript:myBills", async (source) => {
const bills = await new Promise<UnpaidBill[] | null>((resolve) => core.GetUnpaidBills(source, resolve));
if (!bills) return fail("BILLS_UNAVAILABLE");
return { ok: true, bills, total: bills.reduce((sum, b) => sum + b.amount, 0) };
});PayBill
Игрок оплачивает один из своих открытых счетов.
Сторона: сервер · Ожидание: нет · Библиотека: billing.pay
PayBill(source: number, id: string): booleanlocal paid = exports['ai-core']:PayBill(source, billId)Параметры
Prop
Type
Возвращает
boolean: true, когда счёт оплачен. false, когда у игрока нет загруженного персонажа, счёт не его или уже исчез, он не может его оплатить, скрипт счетов отказал или принимает платежи только на собственном экране. В собственных счетах ai-core для личного счёта также нужно, чтобы выставивший был в сети (деньги идут на его банковский счёт).
Пример
import { onClientCallback, resourceExport } from "@aicore-fivem/lib/server";
import { fail, readText } from "@aicore-fivem/lib/shared";
const core = resourceExport("ai-core");
onClientCallback(
"myscript:payBill",
{ args: ([id]) => { const v = readText(id, 64); return v ? [v] : null; }, lock: true },
(source, id) => (core.PayBill(source, id) ? { ok: true } : fail("BILL_NOT_PAID")),
);