Initial how_progression baseline

This commit is contained in:
2026-09-20 17:12:20 +00:00
commit 890a250270
22 changed files with 7258 additions and 0 deletions
+122
View File
@@ -0,0 +1,122 @@
# 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.