Access, blips and place NPCs
readAccess, isPublic, decideAccess, ACCESS_FIELDS, accessFields, readBlipStyle, BLIP_STYLE_FIELDS, PLACE_PED_SPEC, placePedFields and readPlacePed: the panel parts every place shares.
Most places a script adds (a shop, a stash, a garage, a city hall) have the same three panel parts: who may use it, its map blip, and an NPC standing there. Each part comes as a trio: a data spec for your schema.ts, ready panel fields with ai-core's own labels, and a reader for the saved value. Use them so every script's panel looks and behaves the same.
import { readAccess, isPublic, decideAccess, ACCESS_FIELDS, accessFields, readBlipStyle, BLIP_STYLE_FIELDS, PLACE_PED_SPEC, placePedFields, readPlacePed } from "@aicore-fivem/lib/shared";Lua: none of these have a Lua twin (the admin panel is TypeScript only).
Access
The rule is an AccessRule: one of the listed jobs (at its minimum grade, on duty when onDuty is set) or one of the listed gangs (at its minimum grade). Both lists empty means everyone. The client check (allows(rule), see Membership) and the server check (online.allows(source, rule), see Players) use the same decision, so what the player sees matches what the server allows.
readAccess
Reads an access rule from a record's own fields (jobs, gangs, grades, onDuty). Missing fields mean everyone may use it.
Side: Client, server and NUI · Waits: no
readAccess(value: unknown): AccessRuleParameters
Prop
Type
Returns
AccessRule. Names that are not strings are dropped; grades that are not whole numbers of 0 or more are dropped.
Example
import { readAccess } from "@aicore-fivem/lib/shared";
readAccess({ label: "Armoury", jobs: ["police"], grades: { police: 2 }, onDuty: true });
// { jobs: ["police"], gangs: [], grades: { police: 2 }, onDuty: true }isPublic
Whether a rule lets everyone in (no jobs and no gangs listed). Use it to skip checks and to show a place to everyone.
Side: Client, server and NUI · Waits: no
isPublic(rule: AccessRule): booleanParameters
Prop
Type
Returns
true when both jobs and gangs are empty.
Example
import { isPublic, readAccess } from "@aicore-fivem/lib/shared";
isPublic(readAccess({})); // truedecideAccess
The rule's decision from a player's memberships. The client's allows and the server's online.allows call it for you; call it yourself only when you hold the memberships some other way (a NUI page, a test).
Side: Client, server and NUI · Waits: no
decideAccess(
rule: AccessRule,
jobs: ReadonlyArray<{ job: string; grade: number }>,
gangs: ReadonlyArray<{ gang: string; grade: number }>,
dutyJob: string | null,
): booleanParameters
Prop
Type
Returns
true when the rule is public, when a listed gang matches at its minimum grade, or when a listed job matches at its minimum grade (and the player is on duty in it when onDuty is set).
Example
import { decideAccess, readAccess } from "@aicore-fivem/lib/shared";
const rule = readAccess({ jobs: ["police"], grades: { police: 2 }, onDuty: true });
decideAccess(rule, [{ job: "police", grade: 3 }], [], "police"); // true
decideAccess(rule, [{ job: "police", grade: 3 }], [], null); // false: off dutyACCESS_FIELDS
The data spec of the access fields, to spread into the sections of a records file in your schema.ts.
Side: Client, server and NUI · Waits: no
const ACCESS_FIELDS: Record<string, DataSpec>
// { jobs: names with job lookup, optional; gangs: names with gang lookup, optional; onDuty: bool, optional }Example
import { ACCESS_FIELDS } from "@aicore-fivem/lib/shared";
const stashSections = {
label: { type: "text", min: 1, max: 48 },
coords: { type: "vec3" },
...ACCESS_FIELDS,
};accessFields
The panel fields of the access rule (job tags, gang tags, an on-duty switch), with ai-core's own panel labels and hints already set.
Side: Client, server and NUI · Waits: no
accessFields(): WidgetSpec[]Returns
WidgetSpec[]: three fields at the paths jobs, gangs and onDuty. Spread them into the fields of a card in your panel's tabs.
Example
import { accessFields } from "@aicore-fivem/lib/shared";
import type { CardSpec } from "@aicore-fivem/shared";
const accessCard: CardSpec = { icon: "lock", title: "ADMIN_CARD_ACCESS", fields: [...accessFields()] };ACCESS_FIELDS and accessFields() cover jobs, gangs and onDuty only. readAccess also reads grades ({ police: 2 }) when the record has it; without it every listed job or gang needs grade 0.
Blips
readBlipStyle
Reads a blip style from panel data. Each missing or bad part comes from the fallback; values are kept in range (sprite 0-1000, colour 0-100, scale 0.3-2).
Side: Client, server and NUI · Waits: no
readBlipStyle(value: unknown, fallback: BlipStyle): BlipStyleParameters
Prop
Type
Returns
A BlipStyle.
Example
import { readBlipStyle } from "@aicore-fivem/lib/shared";
readBlipStyle({ sprite: 52, color: 500 }, { sprite: 52, color: 2, scale: 0.8 });
// { sprite: 52, color: 100, scale: 0.8 }: colour clamped, scale from the fallbackBLIP_STYLE_FIELDS
The data spec of a blip style's fields, for { type: "object", fields: BLIP_STYLE_FIELDS } in your schema.ts. The panel shows it with its blip widget.
Side: Client, server and NUI · Waits: no
const BLIP_STYLE_FIELDS: Record<string, DataSpec>
// sprite: whole number 0-1000, color: whole number 0-100, scale: number 0.3-2Example
import { BLIP_STYLE_FIELDS } from "@aicore-fivem/lib/shared";
const sections = {
blip: { type: "bool" },
blipStyle: { type: "object", optional: true, fields: BLIP_STYLE_FIELDS },
};Place NPCs
PLACE_PED_SPEC
The data spec of a place's ped section: model, idle scenario and position, all optional. A place without a model has no NPC.
Side: Client, server and NUI · Waits: no
const PLACE_PED_SPEC: DataSpec
// { type: "object", optional: true, fields: { model: text up to 64, scenario: one of the offered scenarios, coords: vec4 } }The scenarios the panel offers: none (stands still), WORLD_HUMAN_STAND_IMPATIENT, WORLD_HUMAN_CLIPBOARD, WORLD_HUMAN_STAND_MOBILE, WORLD_HUMAN_AA_COFFEE, WORLD_HUMAN_SMOKING, WORLD_HUMAN_GUARD_STAND, WORLD_HUMAN_COP_IDLES, WORLD_HUMAN_HANG_OUT_STREET.
Example
import { PLACE_PED_SPEC } from "@aicore-fivem/lib/shared";
const sections = { ped: PLACE_PED_SPEC, label: { type: "text", min: 1, max: 48 } };placePedFields
The panel fields of a place's NPC: a ped model picker, a scenario select and a point tool with heading that snaps to the ground. Labels are ai-core's own.
Side: Client, server and NUI · Waits: no
placePedFields(path?: string): WidgetSpec[]Parameters
Prop
Type
Returns
WidgetSpec[]: three fields at <path>.model, <path>.scenario and <path>.coords.
Example
import { placePedFields } from "@aicore-fivem/lib/shared";
import type { CardSpec } from "@aicore-fivem/shared";
const npcCard: CardSpec = { icon: "user", title: "ADMIN_CARD_NPC", fields: [...placePedFields()] };readPlacePed
Reads a place's NPC from panel data.
Side: Client, server and NUI · Waits: no
readPlacePed(value: unknown): PlacePed | nullParameters
Prop
Type
Returns
A PlacePed, or null when there is no model (the place has no NPC). coords is left out unless all of x, y, z and heading are numbers; an empty scenario is left out.
Example
import { readPlacePed, readBlipStyle, readAccess, str, type PlacePed, type BlipStyle, type AccessRule } from "@aicore-fivem/lib/shared";
export interface Shop {
label: string;
ped: PlacePed | null;
blipStyle: BlipStyle;
access: AccessRule;
}
export function readShop(id: string, v: Record<string, unknown>): Shop {
return {
label: str(v.label, id, 48),
ped: readPlacePed(v.ped),
blipStyle: readBlipStyle(v.blipStyle, { sprite: 52, color: 2, scale: 0.8 }),
access: readAccess(v),
};
}On the client, pass shop.ped ?? undefined as the ped option of a Points point: the point spawns the NPC and puts its target option on it.