AI Skill Report Card
Developing FiveM Framework Scripts
Writes and reviews FiveM resource code enforcing this developer's custom framework conventions, which deliberately diverge from common FiveM community patterns.
Quick Start14 / 15
JavaScript// Proximity-gated loop for a supermarket interaction let supermarketTick = null; AddEventHandler('onClientResourceStart', (resourceName) => { if (GetCurrentResourceName() !== resourceName) return; startSupermarketCheck(); }); function startSupermarketCheck() { setTick(() => { const ped = PlayerPedId(); const playerCoords = GetEntityCoords(ped); const storeCoords = [100.0, 200.0, 30.0]; const dist = exports.Misc.distanceVector(playerCoords, storeCoords); if (dist < 20.0) { if (!supermarketTick) { supermarketTick = setInterval(() => { // supermarket proximity logic here }, 1000); } } else { if (supermarketTick) { clearInterval(supermarketTick); supermarketTick = null; } } }); }
Recommendation▾
Show a 'bad outcome' example where a wrong native is used and flagged, not just correct conversions, to reinforce review use-case
Workflow13 / 15
Progress:
- Identify all native calls and flag disallowed ones (
GetGameTimer,onNet,resourceKvpnatives) - Replace timing calls with
Date.now() - Replace
onNetevent registration withAddEvent/AddEventHandler - Remove any
resourceKvpusage; use in-memory state or framework-provided storage instead - Wrap location-based intervals with a
setTickproximity check usingexports.Misc.distanceVector - Add
exports.Misc.canExecuteguard on any player-triggered event to prevent spam - Verify
clearInterval/clearTickcleanup happens when player leaves proximity or resource stops
Recommendation▾
Clarify what exports.Misc.canExecute signature expects (params/return) since it's used without definition
Rule Reference
| Don't Use | Use Instead | Why |
|---|---|---|
GetGameTimer() | Date.now() | Framework standardizes on JS native timing |
onNet(...) | AddEvent(...) + AddEventHandler(...) | Framework's event system wraps these for consistency |
resourceKvp natives | In-memory objects / framework storage | Unnecessary persistence layer for most use cases |
Unconditional setInterval for proximity logic | setTick check + conditional setInterval | Avoid wasting cycles when player isn't near the relevant location |
| Raw event handlers with no throttling | exports.Misc.canExecute guard | Prevents event spam / exploit abuse |
Manual distance math (Math.sqrt etc.) | exports.Misc.distanceVector | Centralized, tested distance helper |
Examples17 / 20
Example 1: Input:
JavaScriptonNet('shop:buyItem', (itemId) => { const time = GetGameTimer(); // process purchase });
Output:
JavaScriptAddEvent('shop:buyItem'); AddEventHandler('shop:buyItem', (itemId) => { if (!exports.Misc.canExecute(source, 'shop:buyItem', 1000)) return; const time = Date.now(); // process purchase });
Example 2: Input: "Check if player is near the bank every frame and open a menu interval while close." Output:
JavaScriptlet bankTick = null; setTick(() => { const ped = PlayerPedId(); const coords = GetEntityCoords(ped); const bankCoords = [150.0, -100.0, 29.0]; const dist = exports.Misc.distanceVector(coords, bankCoords); if (dist < 15.0 && !bankTick) { bankTick = setInterval(() => { // bank menu prompt logic }, 500); } else if (dist >= 15.0 && bankTick) { clearInterval(bankTick); bankTick = null; } });
Example 3:
Input: "Store player's last login time persistently."
Output: Don't use resourceKvp. Store it via the framework's player data object (e.g., player.data.lastLogin = Date.now()) and persist through the framework's existing database/save layer instead.
Recommendation▾
Add a brief note on Lua equivalents since the skill mentions FiveM Lua/JS but all examples are JS only
Best Practices
- Always null-check and
clearinterval/tick handles on resource stop (onResourceStop) to avoid orphaned loops. - Keep proximity thresholds as named constants, not magic numbers, when a script has multiple zones.
- Apply
exports.Misc.canExecuteon every client-to-server event that can be triggered repeatedly by the player (purchases, interactions, item use). - Prefer one
setTickper logical zone/feature rather than one giant tick checking everything — easier to clear independently. - Use
Date.now()differences (Date.now() - lastActionTime) for cooldown logic instead of frame-based counters.
Common Pitfalls
- Forgetting to clear the
setIntervalwhen the player walks away — causes stacked intervals re-running logic. - Using
onNetout of habit from tutorials/other frameworks — always convert toAddEvent/AddEventHandler. - Reaching for
resourceKvpfor "quick persistence" — it's banned in this framework regardless of convenience. - Skipping
canExecuteon events because "it's just a menu open" — spam protection should be the default, not the exception. - Running distance checks manually instead of
exports.Misc.distanceVector, causing inconsistent threshold behavior across scripts.