# FiveM Port — Feature Porting Guide

## Status

| Layer | Status | Notes |
|---|---|---|
| TypeORM entities (207) | ✅ Copied verbatim | Zero changes needed |
| Express REST API | ✅ Copied verbatim | Zero changes needed |
| Shared constants | ✅ Copied verbatim | |
| Core log/DB/Redis/Mongo | ✅ Copied verbatim | |
| `mp` server shim | ✅ Done | Covers events, players, vehicles, config |
| `mp` client shim | ✅ Done | Covers events, game, gui, browsers→NUI |
| RPC system | ✅ Done | Replaces `mp.events.addProc` |
| Player wrapper | ✅ Done | Wraps FiveM net ID into PlayerMp-compatible object |
| Vehicle wrapper | ✅ Done | Wraps FiveM entity handle |
| CommandSystem | ✅ Done | Uses `RegisterCommand()` per command |
| Server features (101) | 🔲 Not started | See porting order below |
| Client features (~80) | 🔲 Not started | See porting order below |

---

## How to port a server feature

1. **Copy** the feature folder from `game-server/src/features/<name>/` to `fivem-server/src/server/features/<name>/`
2. **Fix imports** — update relative paths (e.g. `../../entities/` → `../../entities/`, `../../core/` stays the same)
3. **Search for `mp.colshapes`** — FiveM has no server colshapes. Replace with the polygon position-tracking system.
4. **Search for `mp.objects.new` / `mp.peds.new`** — use FiveM `CreateObject` / `CreatePed` natives.
5. **Search for `player.call(`** — this works unchanged via `PlayerWrapper.call()`.
6. **Uncomment the import** in `src/server/index.ts` and add to `featuresParallel` or `featuresSeries`.

## How to port a client feature

1. **Copy** the feature folder from `game-client/src/<name>/` to `fivem-server/src/client/features/<name>/`
2. **Fix imports**
3. **Replace `mp.events.addProc`** with `rpc.registerClientProc` from `../core/rpc`
4. **Replace `mp.browsers.new(url).execute(js)`** with `nui.send(type, data)` (PostMessage to Vue)
5. **Replace `mp.game.invoke(hash, ...args)`** with direct native calls where the name is known, or keep `mp.game.invoke` (the shim passes through to `Citizen.invokeNative`)
6. **Uncomment the require** in `src/client/index.ts`

---

## Suggested porting order (server features)

Start with features that have minimal RageMP API surface and no colshape dependency:

1. `shared` — pure data sync
2. `time` — simple, no colshapes
3. `weather` — simple
4. `chat` — core comms, needed by everything
5. `login` — needed before players can do anything
6. `session` — depends on login
7. `player` — needed by commands
8. `permissions` — needed by guards
9. `money` — needed by jobs/most features
10. `inventory` — high-value, many features depend on it
11. `vehicle` — large but critical
12. `job/*` — already on feature/jobsystem branch, good to port early

Defer until late (complex colshape or streaming dependencies):
- `properties` (heavy colshape use → needs polygon system)
- `furniture` (server objects)
- `drugs` (colshapes + objects)
- `graffiti` (colshapes)

---

## RageMP → FiveM cheatsheet

| RageMP (server) | FiveM (server) |
|---|---|
| `mp.events.add('playerJoin', (p) => ...)` | Auto-mapped by shim → `playerConnecting` |
| `mp.events.add('playerQuit', (p) => ...)` | Auto-mapped by shim → `playerDropped` |
| `mp.events.add('myEvent', (p, data) => ...)` | Shim registers net event; player injected from `source` |
| `player.call('event', [a, b])` | `TriggerClientEvent('event', netId, a, b)` |
| `player.notify(msg)` | `TriggerClientEvent('_mp:notify', netId, msg)` |
| `player.setVariable(k, v)` | FiveM StateBag: `Player(id).state.set(k, v, true)` |
| `mp.vehicles.new(model, pos, opts)` | `vehicleRegistry.create(model, pos, opts)` |
| `mp.events.addProc('name', fn)` | `rpc.register('name', fn)` |
| `mp.colshapes.newSphere(...)` | Use polygon position tracking system |
| `mp.players.broadcast(msg)` | `TriggerClientEvent('_mp:chatMessage', -1, msg)` |

| RageMP (client) | FiveM (client) |
|---|---|
| `mp.events.add('render', fn)` | Shim adds to tick loop |
| `mp.events.callRemote('event', ...args)` | `TriggerServerEvent('event', ...args)` |
| `mp.events.addProc('name', fn)` | `rpc.registerClientProc('name', fn)` |
| `mp.players.local.setComponentVariation(...)` | `SetPedComponentVariation(PlayerPedId(), ...)` |
| `mp.game.invoke('0xHASH', ...args)` | `Citizen.invokeNative('0xHASH', ...args)` |
| `mp.browsers.new(url)` | FiveM NUI (declared in `fxmanifest.lua`, one page) |
| `mp.gui.chat.push(msg)` | `TriggerEvent('chat:addMessage', { args: [msg] })` |
