Server event’leri
ai-core’un tetiklediği her server tarafı local event - karakterler, para, meslekler, mesai, çeteler, metadata, tanımlar, eşyalar, ölümler - TypeScript ve Lua’da argümanları ve dinleyicileriyle.
ai-core bu event’leri server’da TriggerEvent ile tetikler (local: diğer server resource’ları duyar, client’lar asla duymaz). Lib’in online aynası ve ESX / QB / vRP köprüleri bunların üstüne kurulmuştur, bu yüzden oyuncuları izlemenin en ucuz yoludur: export çağrısı yok, yoklama yok.
Her event’in handler’ı ai-core değişikliğin ortasındayken senkron çalışır: handler’ları kısa tut ve içlerinde asla bekleme. Beklemen gerekiyorsa (bir veritabanı yazması) bloklamadan başlat.
ai-core:playerLoaded
Bir oyuncunun karakteri yüklendi ve verisi client’ına gönderildi. Karakter yüklemesi başına bir kez tetiklenir, karakter değişiminden sonra da. Doğma seçimi açıkken oyuncu nerede görüneceğini seçmeden önce tetiklenir; seçimin ardından ai-core:playerSpawned gelir.
Taraf: Server · Sabit: CORE.playerLoadedEvent
Argümanlar
Prop
Type
Dinleyici
import { CORE, type CharacterInfo } from "@aicore-fivem/shared";
on(CORE.playerLoadedEvent, (src: number, character: CharacterInfo) => {
console.log(`#${character.id} ${character.firstname} ${character.lastname} loaded (src ${src})`);
});Resource’un başlamadan önce zaten yüklenmiş karakterler bunu senin için asla tetiklemez. Onları yeniden oynatan lib’in onCharacter({ loaded })’ını (Lua’da aiLib.onCharacter) kullan.
ai-core:playerSpawned
Yüklü karakter dünyaya kondu. ai-core:playerLoaded’dan hemen sonra ya da sunucu seçmelerine izin veriyorsa oyuncu bir doğma noktası seçtikten sonra tetiklenir. Dünyada ped gerektiren şeyler için kullan (bir karşılama mesajı, bir ışınlanma).
Taraf: Server · Sabit: CORE.playerSpawnedEvent
Argümanlar
Prop
Type
Dinleyici
import { notify } from "@aicore-fivem/lib/server";
import { CORE } from "@aicore-fivem/shared";
import { Locale } from "common";
on(CORE.playerSpawnedEvent, (src: number, _charId: number) => {
notify(src, Locale("WELCOME_BACK"), "info");
});ai-core:playerUnloaded
Bir karakter bırakılıyor: oyuncu sunucudan ayrıldı ya da karakter ekranına döndü. ai-core karakteri bırakmadan önce tetiklenir, bu yüzden ai-core’un export’ları handler’ının içinde onun için hâlâ cevap verir. Oyuncu başına tuttuğun her şeyi burada temizle.
Taraf: Server · Sabit: CORE.playerUnloadedEvent
Argümanlar
Prop
Type
Dinleyici
import { CORE } from "@aicore-fivem/shared";
const activeJobs = new Map<number, string>();
on(CORE.playerUnloadedEvent, (src: number, _charId: number, reason: "dropped" | "switch") => {
activeJobs.delete(src);
console.log(`${src} unloaded (${reason})`);
});reason = "switch" ile aynı server id bir an sonra başka bir karakter yükleyebilir. Karakter başına verini charId ile anahtarla ya da burada temizle; bir server id’nin tek bir karakteri koruduğunu asla varsayma.
ai-core:moneyChanged
Yüklü bir karakterin bir hesap bakiyesi değişti. Değişiklik uygulandıktan sonra, değişiklik başına bir kez, yalnızca bakiye gerçekten hareket ettiğinde tetiklenir.
Taraf: Server · Sabit: CORE.moneyChangedEvent
Argümanlar
Prop
Type
Dinleyici
import { CORE } from "@aicore-fivem/shared";
// Büyük nakit ödemeleri yetkililer için işaretler.
on(CORE.moneyChangedEvent, (src: number, account: string, balance: number, delta: number, reason: string) => {
if (account === "cash" && delta >= 100_000)
console.log(`${src} got $${delta} cash (${reason}), now $${balance}`);
});ai-core:jobsChanged
Yüklü bir karakterin sahip olduğu meslekler listesi değişti: bir meslek eklendi ya da kaldırıldı veya bir rütbe değişti.
Taraf: Server · Sabit: CORE.jobsChangedEvent
Argümanlar
Prop
Type
Dinleyici
import { CORE, type JobMembership } from "@aicore-fivem/shared";
on(CORE.jobsChangedEvent, (src: number, jobs: JobMembership[]) => {
const police = jobs.find((m) => m.job === "police");
console.log(police ? `${src} is police grade ${police.grade}` : `${src} is not police`);
});ai-core:dutyChanged
Yüklü bir karakter bir meslekte mesaiye girdi ya da mesaiden çıktı. Bir oyuncu aynı anda en fazla bir meslekte mesaidedir.
Taraf: Server · Sabit: CORE.dutyChangedEvent
Argümanlar
Prop
Type
Dinleyici
import { CORE } from "@aicore-fivem/shared";
on(CORE.dutyChangedEvent, (src: number, job: string | null) => {
console.log(job ? `${src} on duty: ${job}` : `${src} off duty`);
});Bir meslekte kaç oyuncunun mesaide olduğunu öğrenmek için bu event’leri kendin saymak yerine GlobalState ai:duty:<job>’ı oku (bkz. State bag’ler).
ai-core:gangsChanged
Yüklü bir karakterin ait olduğu çeteler listesi değişti: bir çete eklendi ya da kaldırıldı veya bir rütbe değişti.
Taraf: Server · Sabit: CORE.gangsChangedEvent
Argümanlar
Prop
Type
Dinleyici
import { CORE, type GangMembership } from "@aicore-fivem/shared";
on(CORE.gangsChangedEvent, (src: number, gangs: GangMembership[]) => {
console.log(`${src} is in ${gangs.length} gang(s)`);
});ai-core:activeGangChanged
Yüklü bir karakter adına hareket ettiği çeteyi değiştirdi ya da artık hiçbiri adına hareket etmiyor.
Taraf: Server · Sabit: CORE.activeGangChangedEvent
Argümanlar
Prop
Type
Dinleyici
import { CORE } from "@aicore-fivem/shared";
on(CORE.activeGangChangedEvent, (src: number, gang: string | null) => {
console.log(`${src} now acts for ${gang ?? "no gang"}`);
});ai-core:metaChanged
Yüklü bir karakterin bir metadata değeri değişti. Metadata, karakterle birlikte saklanan serbest bir anahtar / değer çantasıdır; ESX / QB köprüleri framework metadata’sını (açlık, susuzluk, stres, isdead...) orada tutar.
Taraf: Server · Sabit: CORE.metaChangedEvent
Argümanlar
Prop
Type
Dinleyici
import { CORE } from "@aicore-fivem/shared";
on(CORE.metaChangedEvent, (src: number, key: string, value: unknown) => {
if (key === "stress" && typeof value === "number" && value >= 90)
console.log(`${src} is very stressed`);
});ai-core:definitionsChanged
Admin panelinde bir meslek ya da çete eklendi, değiştirildi veya silindi. Değişen her meslek ya da çete için bir kez tetiklenir.
Taraf: Server · Sabit: CORE.definitionsChangedEvent
Argümanlar
Prop
Type
Dinleyici
import { CORE } from "@aicore-fivem/shared";
const labelCache = new Map<string, string>();
// Panel o mesleği değiştirdiğinde önbellekteki bir etiketi at.
on(CORE.definitionsChangedEvent, (file: "jobs" | "gangs", name: string) => {
if (file === "jobs") labelCache.delete(name);
});ai-core:characterScreen
Bir oyuncunun karakter ekranı yükleniyor (katıldıktan ya da ona döndükten sonra). ai-core kartların görünümlerini kendisi okur; bir kıyafet script’i kartlara portre çizmek için dinler.
Taraf: Server · Sabit: CORE.characterScreenEvent
Argümanlar
Prop
Type
Dinleyici
import { CORE } from "@aicore-fivem/shared";
on(CORE.characterScreenEvent, (src: number, charIds: number[]) => {
console.log(`${src} sees ${charIds.length} character card(s)`);
});ai-core:inventoryChanged
ai-core’un envanter katmanının arkasındaki envanter değişti: seçilen envanter başladı ya da durdu veya sahibi panelde başka birini seçti. Eski envanterden önbelleğe aldığın her şeyi at (eşya etiketleri, tanımlar).
Taraf: Server · Sabit: CORE.inventoryChangedEvent
Argümanlar
Prop
Type
Dinleyici
import { CORE } from "@aicore-fivem/shared";
let itemLabels: Record<string, string> | null = null;
on(CORE.inventoryChangedEvent, (resource: string | null) => {
itemLabels = null; // bir sonraki kullanımda yeni envanterden tekrar oku
console.log(`inventory is now ${resource ?? "none"}`);
});ai-core:itemUsed
Bir oyuncu bir eşya kullandı. Eşyanın verdiği ihtiyaçları (açlık, susuzluk, stres) taşır, böylece bir HUD ya da ihtiyaç script’i envanteri bilmeden onları uygular. ai-hud bunu dinler.
Taraf: Server · Sabit: CORE.itemUsedEvent
Argümanlar
Prop
Type
Dinleyici
import { CORE } from "@aicore-fivem/shared";
on(CORE.itemUsedEvent, (src: number, name: string, status: Record<string, number> | null) => {
if (!status) return;
for (const [need, amount] of Object.entries(status))
console.log(`${src} used ${name}: ${need} ${amount > 0 ? "+" : ""}${amount}`);
});Bugün eşya kullanımlarını ai-core’a yalnızca ai-inventory bildirir: başka bir envanterle bu event tetiklenmez. Bir envanterin kendi kullanım event’ini değil bu event’i dinle, böylece script’in envanter ai-inventory iken çalışır ve başkaları eklendiğinde de çalışmaya devam eder.
ai-core:playerDied
Yüklü karakteri olan bir oyuncu öldü. ai-core bunu FXServer’ın kendi ped ölüm raporundan alır (FXServer 38039 ya da daha yeni), bu yüzden hiçbir client’a güvenilmez.
Taraf: Server · Sabit: CORE.playerDiedEvent
Argümanlar
Prop
Type
Dinleyici
import { CORE } from "@aicore-fivem/shared";
on(CORE.playerDiedEvent, (src: number, killer: number | null, weaponHash: number) => {
if (killer !== null && killer !== src)
console.log(`${GetPlayerName(String(killer))} killed ${GetPlayerName(String(src))} (weapon ${weaponHash})`);
});Bu, ölüm script’inin "yerde" durumu değil, oyunun ölümüdür: bir ölüm script’i yerdeki bir oyuncuyu canlandırmak için canlı tutabilir. "Bu oyuncu yerde mi" için server lib’inin medical’ını ya da ai-core’un server sağlık export’larını kullan.
ai-core:vrp:config
Sunucu sahibi ai-core’un panelinde vRP eşlemesini değiştirdi ("vRP scripts" sekmesi). ai-core’un vRP köprüsü bunu dinler; yalnızca vRP eşlemesini kendin okuyorsan ihtiyacın olur.
Taraf: Server · Sabit: VRP.configEvent
Argümanlar
Prop
Type
Dinleyici
import { VRP, type VrpConfig } from "@aicore-fivem/shared";
on(VRP.configEvent, (config: VrpConfig) => {
console.log(`${config.permissions.length} vRP permission rule(s)`);
});Diğer ai-* script’lerinin event’leri
Bunları ai-core değil ai-* script’leri tetikler, ama birçok resource onları dinler. Tam başvuruları her script’in developer sayfasındadır.
ai-vehicles:owners
Bellekteki sahipli araçların sahipleri değişti (bir karakter garajıyla yüklendi, bir araç satın alındı, satıldı ya da silindi). Server tick’i başına en fazla bir kez, o tick’in her değişikliğiyle tetiklenir. Anahtar script’leri her seferinde ai-vehicles’a sormadan plakadan sahibe bir harita tutmak için bunu kullanır.
Taraf: Server · Sabit: VEHICLES_EVENTS.owners
Argümanlar
Prop
Type
Dinleyici
import { resourceExport } from "@aicore-fivem/lib/server";
import { VEHICLES_EVENTS } from "@aicore-fivem/shared";
const owners = new Map<string, string>();
// Tam listeden başla, sonra değişiklikleri izle.
for (const [plate, type, id] of resourceExport("ai-vehicles").GetPlateOwners()) owners.set(plate, `${type}:${id}`);
on(VEHICLES_EVENTS.owners, (puts: Array<[string, string, string]>, removes: string[]) => {
for (const [plate, type, id] of puts) owners.set(plate, `${type}:${id}`);
for (const plate of removes) owners.delete(plate);
});chatMessage
ai-chat, bir oyuncunun mesajını iletmeden önce klasik FiveM chatMessage event’ini tetikler. Handler’ında CancelEvent() çağırmak mesajı atar.
Taraf: Server · Sabit: yok (FiveM’in kendi adı)
Argümanlar
Prop
Type
Dinleyici
on("chatMessage", (source: number, _author: string, text: string) => {
if (text.toLowerCase().includes("discord.gg")) {
CancelEvent();
console.log(`blocked an invite link from ${source}`);
}
});Event’ler ve durum
ai-core diğer script’lere bir şeyin değiştiğini nasıl söyler - local event’ler, net event’ler, state bag’ler - ve TypeScript ile Lua’da nasıl dinlenir.
Client event’leri
ai-core’un tetiklediği her client tarafı local event - yerel karakter yüklendi ya da kaldırıldı, yerde olma durumu, önbellekteki değerler, HUD görünürlüğü, dünya senkronu, meslek tanımları, tuş ipuçları, emniyet kemeri - argümanları ve dinleyicileriyle.