# 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//` to `fivem-server/src/server/features//` 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//` to `fivem-server/src/client/features//` 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] })` |