Your first gamemode
Create a gamemode, start it on your server and set up your editor.
You need a running server (see Running a server) and Node.js 22.18 or newer.
1. Create the folder
A gamemode is a folder in gamemodes/ with an index.ts. The easiest start is a copy of the example:
gamemodes/
freeroam/ the example that comes with the server
mymode/ your copy
index.ts entry point - the server starts this file
tsconfig.json editor settings (type checking)
package.json only for type checkingOr start empty with just an index.ts:
mp.log("mymode loaded")
// Where everyone starts - every gamemode needs this (step 3)
mp.events.on("gamemodeStarted", () => {
mp.world.setSpawn({ city: "berlin", vehicle: "scania_r_2016" })
})
mp.events.on("playerJoin", (player) => {
mp.chat.send(player, `Hello ${player.name}, welcome to ${mp.server.name}!`)
})2. Turn it on
List it in server.cfg. Several gamemodes can run at the same time:
gamemodes = [mymode]
# or together with the example:
gamemodes = [freeroam, mymode]Start the server. Its log shows that the gamemode was loaded:
[mymode] mymode loaded3. Set the standard spawn
Every session on an Open Road MP server is a fresh career: the player's single-player save is not loaded, so they arrive without a truck, without a garage and without money. Your gamemode decides where they start and what they drive - set a standard spawn with mp.world.setSpawn. Without one, players start wherever the game puts them, which may be off the road.
mp.events.on("gamemodeStarted", () => {
mp.world.setSpawn({ city: "berlin", vehicle: "scania_r_2016" })
})
mp.events.on("playerJoin", (player) => {
mp.players.setMoney(player, 5000) // a fresh career has no money
})What the player sees:
- They join and the world loads. The game shows its desktop (and, the first time, asks for a home city).
- They press Drive and get the
vehicleof the spawn. - Open Road MP puts them at the spawn, ready to go.
Set it in gamemodeStarted: by then mp.world knows all cities and depots, and the spawn is checked right away (an unknown city throws an error into your log). The spawn takes one of three forms, each with an optional vehicle:
| Spawn | Where |
|---|---|
{ city: "berlin" } | a random depot of the city - players start at different depots |
{ company: "tradeaux", city: "dusseldorf" } | that depot, everyone at the same spot |
{ position: { x, y, z }, heading: 90 } | an exact point on the map, heading in degrees (0 = north) |
- City and company ids come from the game data:
mp.world.cities()andmp.world.companies({ city })list them. The live map shows positions. vehicleis the truck players get with Drive: a name likeplayers.setVehicletakes ("scania_r_2016","daf_2021"...). Without it, the server'sfallback_vehiclefromserver.cfgis used (mp.players.setFallbackVehiclechanges it per player).- When it applies: on
playerReady, before your ownplayerReadyhandlers. If the player has no truck yet, Open Road MP keeps the spot and moves them there as soon as they have one. - Change it any time with another
mp.world.setSpawn(...); it is used for everyone who joins from then on.mp.world.setSpawn(null)removes it. - Different spawns per player (e.g. by team): leave the standard spawn out and teleport in your own
playerReadyhandler withmp.players.teleportToCity/teleportToCompany/teleport- it waits for the truck the same way.
The example gamemode freeroam sets its spawn from spawnCity and spawnTruck in its settings.ts.
4. Change and reload
Changes to your code take effect after a restart of the gamemode - the server keeps running, players stay connected. Type in the server console:
gamemode restart mymodeBefore every start the server type-checks the gamemode against the mp API (TypeScript, strict). With errors it does not start it and lists them in the log:
[mymode] index.ts(12,14): TS2551: Property 'setMony' does not exist on type 'PlayersApi'. Did you mean 'setMoney'?
Gamemode mymode not started: 1 type check error. Fix, then run "gamemode restart mymode".So a typo shows up at once, not when a player first runs into it. Fix it and restart.
5. Editor support
Open the gamemode folder in VS Code (or any editor with TypeScript support). With the tsconfig.json from the example, the editor knows the whole mp API: it completes names, shows the descriptions and marks mistakes.
It is the same check the server runs. To check all files at once from the command line:
cd gamemodes/mymode
npm install
npm run checkTypeScript in Node.js
Node.js runs your .ts files directly by removing the types. That works for almost all TypeScript, with a few rules:
- Import your own files with the extension:
import { formatEuro } from "./util.ts". - Not allowed:
enum,namespacewith content and parameter properties in constructors (constructor(private x: number)). Thetsconfig.jsonof the example (erasableSyntaxOnly) marks them. - Files are ES modules:
import/export, top-levelawaitworks. - Everything Node.js offers is available:
setTimeout/setInterval,fetch,node:fs...
// A message every 15 minutes
setInterval(() => {
mp.chat.broadcast("Drive safely - and take a break now and then.")
}, 15 * 60 * 1000)Next: Events - reacting to what happens on the server.