123 lines
16 KiB
Markdown
123 lines
16 KiB
Markdown
# How Progression: current inventory and migration plan
|
||
|
||
This describes the live `client.lua` and `server.lua` as audited in September 2026 and the planned migration. The `.bak*` and `.pre-*` files are historical copies; `fxmanifest.lua` still runs only `client.lua` and `server.lua` as gameplay entry points. Do not infer live behavior from the copies.
|
||
|
||
## Live inventory
|
||
|
||
| Area | Implemented behavior |
|
||
| --- | --- |
|
||
| Introduction | Appearance save triggers UNKNOWN's one-time NPWD SMS and sets `unknown_introduced` and Crowbar stage 1. Login sync restores Crowbar and Mack/Vinny state. `/testunknown` and `/prog unknown` exercise it. |
|
||
| Crowbar world | Local Clay ped, smoking scenario, talk target, map blip, locked frozen Daemon. Talk dialog chooses missions by `crowbar_stage`; active mission suppresses interaction. |
|
||
| Crowbar 1, The Introduction | Server-spawned Emperor, crew keys, retrieve/return objectives and blips/marker; initiator gets $500, eligible crew get 5 Crowbar REP and stage 2. Startup removes leftover mission Emperors. |
|
||
| Crowbar 2, Get Some Wheels | Server-spawned locked Premier, three lockpicks per participant; delivery persists a Premier through `qbx_vehicles:CreatePlayerVehicle` for the owner, with submitted properties; eligible crew get 5 REP/stage 3 and Crowbar SMS. Physical mission Premier is deliberately retained. |
|
||
| Crowbar 3, Quick Score | Harmony store index 13, one unloaded pistol to initiator; `ff_storerobbery` event advances from robbery to losing police. Client escape monitoring completes; eligible crew get 5 REP/stage 4 and marked-cash SMS. |
|
||
| Crowbar 4, Wash the Cash | Mack dialog opens Gabe route, Gabe/money-wash event advances objective, `randol_moneywash` completion event ends mission; eligible crew get 5 REP/stage 5 and Crowbar SMS. Mack stage becomes 1 when spoken to. Gabe is currently a blip/location, not a spawned ped here. |
|
||
| Crowbar 5, Buy In | Temporary ox_inventory stash with `crowbar_package`, permanent local crate/target, inventory swap hook, package-carrier ambush with two trucks and Lost peds, escape/return objective, death removes package. Eligible crew get 5 REP/stage 6; carrier gets $750. |
|
||
| Mack world | Mack ped and Deke ped physically spawn at resource start, plus festival bus, damaged Emperor, forklift, six wandering workers. Mack interaction is gated by server state; blip is unlocked separately. Deke opens ox_inventory `DekeTools`. |
|
||
| Mack 1, Easy Rider | Accepted crew each get `WEAPON_BAT`; initiator spawns 1–5 mission Sanchezes. Leave yard, trash detour car, deliver bikes to Vinny, then speak to Vinny. Server tracks delivered bike indices and crew state; each eligible participant gets $300, 5 Mack REP and stage 2. Several Mack SMS messages drive the detour. |
|
||
| Vinny world/service | Vinny ped/blip and five local locked frozen display Sanchezes; target calls existing `qbx_vehicleshop` purchase. Delayed SMS 60–90 seconds after Easy Rider completion saves `vinny_fence_unlocked`. Persistent fence marker allows up to three unowned non-mission Sanchezes per player per game day for one `markedbills` item worth $200 each. Server checks ownership, location, quota, item capacity and vehicle deletion. |
|
||
| Cosmic Dave | Local Omega ped with partying scenario; no blip, interaction, phone behavior or mission in this resource yet. |
|
||
| Other | `useBodyArmor` ox_inventory item export; NPWD contact bridge; `/testcontact`, `/givemarked`, `/skipcrowbar1`, `/prog`. |
|
||
|
||
## Responsibilities in current files
|
||
|
||
`fxmanifest.lua` declares ox_lib, oxmysql and runtime dependencies and loads one gameplay script per side. `client.lua` mixes contact presentation, dialogs, local scenery, mission vehicles/peds/props, blips/GPS, per-frame markers, mission polling, targeting, inventory use and NPWD UI bridge. `server.lua` mixes schema alteration, SQL reads/writes, crew snapshots/rewards/tracker, phone SMS, mission registration/state, entity validation, fence economy, login restoration, developer commands and cleanup. Passive contact/location definitions and an unregistered mission framework now exist; neither drives current gameplay.
|
||
|
||
## Foundation implemented, migration pending
|
||
|
||
`shared/contacts/*.lua` holds seven passive story contact definitions; `shared/contacts/init.lua` checks IDs and permanent phone-number uniqueness when required. `shared/locations.lua` mirrors mission locations, `shared/mission_ids.lua` defines string mission/phase IDs and parses human `/prog` notation, and `server/services/mission_registry.lua` supplies an instance registry without registering missions or events. `shared/debug_contact.lua` records the temporary Michael fixture's avatar separately. The manifest packages shared files but does not run them. Legacy `client.lua` and `server.lua` remain authoritative for every active spawn, interaction, mission, SMS, SQL write, event, callback, export and command. Definitions are verified copies and become authoritative only as individual systems migrate.
|
||
|
||
## Proposed layout
|
||
|
||
```text
|
||
how_progression/
|
||
fxmanifest.lua
|
||
shared/
|
||
contacts/{unknown,crowbar,mack,gabe,deke,vinny,cosmic_dave}.lua
|
||
locations.lua
|
||
mission_ids.lua
|
||
client/
|
||
bootstrap.lua
|
||
services/{contacts,world,markers,routes,phone,mission_view}.lua
|
||
missions/crowbar/{introduction,get_some_wheels,quick_score,wash_the_cash,buy_in}.lua
|
||
missions/mack/easy_rider.lua
|
||
services/body_armor.lua
|
||
server/
|
||
bootstrap.lua
|
||
services/{progression,phone,participants,crew_tracker,rewards,mission_registry,entities,restoration}.lua
|
||
missions/crowbar/{introduction,get_some_wheels,quick_score,wash_the_cash,buy_in}.lua
|
||
missions/mack/easy_rider.lua
|
||
services/vinny_fence.lua
|
||
debug/{commands,phases}.lua
|
||
docs/{ARCHITECTURE,MISSION_DESIGN,PROGRESSION,CONTACTS,PHONE,CREWS}.md
|
||
```
|
||
|
||
Files under `shared/contacts` are data descriptors, with optional explicit callback IDs for interactions. Functions, live handles and side effects belong in services. Contact descriptors should allow `world.alwaysPresent` independent of `services.requires`, `blip.requires`, and `phone.requires`. Use ordered manifest loading or explicit `require` with one bootstrap; do not duplicate event registration during migration. No new SQL table or phone-number allocator is required for this layout.
|
||
|
||
## Move map (preserve event/export names)
|
||
|
||
| Current functions/events or blocks | Destination |
|
||
| --- | --- |
|
||
| `getProgression`, `getPlayerProgression`, `setCrowbarProgression`, `advanceCrowbar`, schema ALTER and SQL projection | `server/services/progression.lua`; preserve existing columns and initialization timing |
|
||
| `syncProgressionState`, player-loaded/appearance hooks; client `syncProgression`, initial world thread, unload/reset | `server/services/restoration.lua`, `client/bootstrap.lua`, `client/services/world.lua` |
|
||
| `sendSmsToPlayer`, UNKNOWN introduction, `addPhoneContact` bridge | `server/services/phone.lua`, `client/services/phone.lua`; introduction trigger in contact/mission orchestration |
|
||
| `getMissionParticipants`, `getCitizenIdFromSource`, `participantIsValid` | `server/services/participants.lua` |
|
||
| `rewardCrowbarParticipants`, `rewardMackParticipants`, mission cash/items | `server/services/rewards.lua`, with mission-specific reward declarations |
|
||
| Repeated `*MissionN`, `*MissionNByCitizenId`, `clear/start/complete`, active lookup | `server/services/mission_registry.lua` plus individual server mission files |
|
||
| All `start/phase/cleanup/reward` client events, mission polling and spawned mission entities | Corresponding `client/missions/<contact>/<mission>.lua` |
|
||
| `createCrowbar`, `createMack`, `createDeke`, `createVinny`, `createCosmicDave`, display bikes and scrapyard ambience | Contact definitions plus `client/services/contacts.lua` and `client/services/world.lua` |
|
||
| `create*Blip`, `setMackMission1Route`, all `SetNewWaypoint`, mission/fence `DrawMarker` threads | `client/services/routes.lua` and `markers.lua`, driven by objective views |
|
||
| All `updatePartyTasks`/`sendPartyNotification` calls | `server/services/crew_tracker.lua`; preserve exact task labels and status types initially |
|
||
| `fenceSanchez`, fence count/day, leave-bike event | `server/services/vinny_fence.lua`, `client/services/world.lua`; keep separate from Easy Rider mission |
|
||
| `/prog`, `/testunknown`, `/skipcrowbar1`, `/givemarked`, `/testcontact` | `server/debug/commands.lua` and `phases.lua` |
|
||
| `useBodyArmor` export | `client/services/body_armor.lua`; preserve export name used by ox_inventory |
|
||
| `onResourceStop`, mission entity deletion and local target cleanup | Each module's cleanup registered through one lifecycle coordinator |
|
||
|
||
The move map covers the public event families listed in each mission section, not a rename plan. Keep current event names during extraction so external resources and running clients continue to communicate.
|
||
|
||
### Public handler inventory by destination
|
||
|
||
Keep these names while moving handlers. `client:` and `server:` below expand to `how_progression:client:` and `how_progression:server:`.
|
||
|
||
| Destination | Existing handlers/callbacks |
|
||
| --- | --- |
|
||
| Restoration/contact services | `client:unlockCrowbar`, `client:syncProgression`, `client:unlockMack`, `client:unlockGabe`, `client:resetProgression`, `client:unlockVinnyFence`; `QBCore:Client:OnPlayerUnload`, `QBCore:Server:OnPlayerLoaded`, `illenium-appearance:server:saveAppearance`; `server:getCrowbarMission`, `server:isCrowbarMissionActive`, `server:canTalkToMack` |
|
||
| Crowbar 1 | `server:startCrowbarMission1`, `server:crowbarMission1VehicleAcquired`, `server:completeCrowbarMission1`; `client:startCrowbarMission1`, `client:crowbarMission1Return`, `client:cleanupCrowbarMission1`, `client:crowbarMission1Reward` |
|
||
| Crowbar 2 | `server:startCrowbarMission2`, `server:completeCrowbarMission2`; `client:startCrowbarMission2`, `client:cleanupCrowbarMission2` |
|
||
| Crowbar 3 | `server:startCrowbarMission3`, local `server:storeRegisterRobbed` from `ff_storerobbery`, `server:completeCrowbarMission3`; `client:startCrowbarMission3`, `client:crowbarMission3Escape` |
|
||
| Crowbar 4 | `server:startCrowbarMission4`, `server:getCrowbarMission4State`, `server:crowbarMission4TalkedToMack`, local `server:moneywashStarted`, local `server:moneyWashed`; `client:startCrowbarMission4`, `client:crowbarMission4Mack`, `client:crowbarMission4Gabe`, `client:cleanupCrowbarMission4` |
|
||
| Crowbar 5 | `server:startCrowbarMission5`, `server:crowbarMission5Escaped`, `server:completeCrowbarMission5`, `server:crowbarPackageCarrierDied`; `client:startCrowbarMission5`, `client:crowbarMission5PackageTaken`, `client:crowbarMission5Escaped`, `client:cleanupCrowbarMission5`, `client:crowbarMission5Complete`; `baseevents:onPlayerDied`, `baseevents:onPlayerKilled`, ox_inventory `swapItems` hook |
|
||
| Easy Rider | `server:startMackMission1`, `server:mackMission1BikeSpawned`, `server:mackMission1Detour`, `server:mackMission1AtDetour`, `server:mackMission1CarTrashed`, `server:mackMission1BikeDelivered`, `server:completeMackMission1`, `server:getMackMission1State`; `client:startMackMission1`, `client:mackMission1TrashCar`, `client:mackMission1DetourExplained`, `client:mackMission1DeliverBikes`, `client:mackMission1DeliveryCount`, `client:mackMission1TalkVinny`, `client:mackMission1Complete` |
|
||
| Rewards | `client:crowbarReward`, `client:mackReward` |
|
||
| Vinny fence | `server:fenceSanchez`, `client:leaveFenceBike` (unlock event listed under restoration) |
|
||
| Phone | `client:addPhoneContact`; NPWD exports are calls, not how_progression event registrations |
|
||
| Lifecycle | `onResourceStop` server handler; client cleanup currently spread across unload and mission handlers |
|
||
|
||
The body-armor `useBodyArmor` client export and commands `/testunknown`, `/skipcrowbar1`, `/prog`, `/givemarked`, `/testcontact` are also public interfaces. No handler for Gabe/Deke/Cosmic Dave missions exists today.
|
||
|
||
## Migration order and gates
|
||
|
||
1. Freeze a behavior inventory: event names, SQL columns, item names, text, coordinates, rewards, phase behavior and external call sites. Record a small solo/crew smoke test for every live mission and `/prog` branch.
|
||
2. Add shared contact/location data without switching runtime use. Verify values against live Lua. Move only pure constants and phone numbers into descriptors; reload and test contact visibility.
|
||
3. Extract server progression, phone and participant helpers behind existing call signatures. Keep SQL and NPWD calls identical. Test login, SMS, stage sync and one crew snapshot.
|
||
4. Extract client world, contact ped/asset, blip and marker services while preserving physical spawn timing and gated access separately. Test reconnect, repeated sync, resource restart and reset.
|
||
5. Add mission registry and crew tracker adapters, initially routing to old mission handlers. Preserve exact task payloads and `citizenid` maps. Test solo/crew eligibility.
|
||
6. Move one complete mission at a time, with its client and server parts together: Crowbar 1–5, then Easy Rider. At each step, run start, phase, completion, abort/reset and reconnect checks. Do not move a shared helper simultaneously with a mission unless required.
|
||
7. Extract Vinny fence, body-armor export and debug commands. Implement deterministic `/prog` reconstruction one mission/phase at a time, preserving existing shorthand until replaced and tested.
|
||
8. Once all callers use modules, remove the old live blocks only after event/export and in-game parity checks. Historical copies remain untouched unless separately approved.
|
||
|
||
Every intermediate manifest must load each event, callback and export exactly once. Keep `client.lua`/`server.lua` as temporary bootstraps if that makes extraction safer.
|
||
|
||
## Risks and audit findings
|
||
|
||
- The SQL table creation DDL is not in this resource; only the three Vinny fence columns are altered at startup. Inspect the live schema before changing SQL. `getProgression` inserts a default row and then reads it.
|
||
- Mission state is memory-only, generally one global instance per mission plus a citizenid map. Resource restart loses active mission state. Existing stop cleanup explicitly deletes only Crowbar 1/2 server vehicles. Client world assets/targets and other mission entities have uneven cleanup. Treat as migration risks, not permission to change gameplay in the extraction pass.
|
||
- Several mission starts call `clear*` on a global mission, which can replace another crew's mission. Easy Rider instead rejects a concurrent start. Preserve current behavior until a separate multiplayer design decision.
|
||
- `participantIsValid` compares the snapshotted source's current citizenid; a reconnect with a new source does not regain active mission participation. This is distinct from durable identity for progression. Improve through citizenid resolution only with deliberate mission-lifecycle tests.
|
||
- `clearMackMission1`, `setCrowbarProgression`, `advanceCrowbar`, and client `unlockMack`/`unlockGabe` have no in-resource caller in the live files. They may be intended APIs/legacy; search external call sites before removal. `testcontact` intentionally randomizes a temporary Michael number; it must not influence permanent contact numbers.
|
||
- `/prog` parses integer text components rather than Lua floats, but current shortcuts depend on an already active mission for most later phases; phase 5.3 has a distinct client event path. These are not deterministic reconstruction yet.
|
||
- `getCrowbarActiveMission` and `getMackMission1State` are separate lookup paths. Crew task status values mix `true/false` and `current/pending/done`; standardize only after confirming `bs_groupsystem` behavior.
|
||
- The resource uses `ff_storerobbery`, `randol_moneywash`, `qbx_vehicles`, `qbx_vehicleshop`, `ox_inventory`, `ox_target`, `qbx_vehiclekeys`, NPWD and `bs_groupsystem` APIs beyond the manifest dependency list. Preserve server.cfg ordering; inspect installed APIs before adding dependencies.
|
||
- The Vinny daily quota uses a client-provided GTA calendar date and SQL count. The server validates shape and monotonicity but does not independently derive the game day. This is a trust boundary to review separately.
|
||
- `client.lua.bak*` and `server.lua.bak*` are not loaded, but are numerous and easy to mistake for live code. Keep a clear live-file index; do not delete them as incidental cleanup.
|