Skip to content

Setting up

Everything on this page holds whatever language you script in; the language pages start where this one ends.

  • The game - Kingdom Come: Deliverance II on Steam, from the Microsoft Store (the Xbox app, PC Game Pass) or from the Epic Games Store, the build the current KCD:MP release was made for (the release notes say which). The server itself does not need the game, but the world data it wants is exported from a copy of it.
  • The KCD:MP client - the launcher and the client, from the download page at kcd-mp.com, on every machine that plays. The launcher starts the game with KCD:MP inside it and connects it to a server. Unpack it anywhere once; from then on the launcher tells you when a newer release is out and updates itself on your say-so.
  • The server folder - the dedicated server, from the same download page under Host your own: one archive with a windows/ and a linux/ folder inside; unpack it and take the folder for your system. It is a .NET 10 program: the machine that runs it installs the .NET 10 runtime once. A server needs one UDP port (7777 by default).

The folder is the same on both systems:

KcdMp.Server (.exe) the server
server.toml.example every setting, every key documented; the first start copies it to server.toml, the file you edit
gamemodes/ the game modes: freeroam.lua, basicrp.lua, duel_arena.lua, the marker example (a mode with a client half) and a README
sdk/ what your editor and a C# project use: KcdMp.Api.dll + .xml, KcdMp.d.lua, KcdMp-client.d.lua, KcdMp-web.d.ts -
and web/: example web interfaces and a React + TypeScript starter
data/ what the server keeps (the world's doors, chests and bans) and reads (the game's tables, the world data) - with a README
tools/ Windows only: the exporters that make the game's data from your own copy of the game

server.toml is read from the working directory (or --config <path>); every key is optional and Server configuration lists them all with their defaults. A command-line flag overrides the file (--max-players 64 beats [server] max_players).

The settings ship as server.toml.example. The first start copies it to server.toml (you can also copy it yourself before that), and server.toml is the file to edit: a new version unpacked over the folder replaces only the example, so your settings survive every update. After an update, compare the two files to see the keys that are new.

Run the server in its folder - KcdMp.Server.exe on Windows, ./KcdMp.Server on Linux - and read its first lines: the version and the protocol number, the tick rate, which game mode it loaded, and one line per data file it found or could not use (combat tables: ..., heightmap: ..., navmesh: ..., collision: ...). A missing file turns one thing off and nothing else; the server runs without any of them. Ctrl+C stops it; --version prints the version and exits. A server that gets stuck - unable to send or receive for 30 seconds - ends itself with exit code 3 ([server] stall_exit), so have whatever starts it start it again when it stops.

Two settings are worth a look before anyone else joins:

[server]
name = "KCD:MP dev server" # what the players see in the launcher
password = "" # "" = anyone may join
[master]
url = "https://kcd-mp.com/server-list" # the public list; "" = announce nowhere, a private server

A server announces itself to the public list by default, so a test server is best made private (url = "") or passworded until it is meant to be found. Putting a server on the list has the rest - the port, the address the list should show, what players see.

Open the launcher (with Steam running for the Steam copy of the game), type the name the other players will see, and connect: Servers lists the public list, Direct connect takes an address - 127.0.0.1:7777 for a server on the same machine, the machine’s address on a LAN. The launcher asks the server for its level and boots the game onto it; the first load takes a little longer than usual. In the game, Enter opens the chat and Page Up / Page Down scroll back through it (the launcher’s Options change those two keys), Tab the scoreboard, Esc the menu, G the emote wheel (hold T to point); /help in the chat lists the commands the server answers.

The server does not have the game. Four files, each made once from your own copy of it with the tools in tools/ (Windows - the machine the game is installed on) and put under data/, give it what it lacks; a server on Linux gets the files copied over. Each is one job, one guide:

File What it turns on Guide
data/combat/items.json damage from the game’s own weapon and armour tables; items, souls, buffs and meshes by name (/give shortswordBroad, a horse breed by name, a potion the server owns); the reference lists as the server resolves them; what the audit tells the items apart by - without it the item check is passive Exporting the game’s tables
data/heightmaps/<level>.hmap the terrain check - a player far under or over the ground is pulled back - and the terrain height for a game mode Exporting the terrain
data/navmesh/<level>.knav NPC actors that walk around walls instead of into them; paths and reachability for a game mode Exporting the navigation mesh
data/collision/<level>.kcol line of sight on hits and shots, the floor under a player as the ground, rays for a game mode Exporting the collision geometry

Do the tables first: without them the server knows items, souls and buffs by their GUIDs only, takes the damage the players’ games report and cannot judge what players carry (the item check follows what their games say and removes nothing). Export them again after every update of the server. The other three are per level and can wait until the server needs them.

[gamemode] script names it; the command line (--gamemode gamemodes/duel_arena.lua) wins over the file:

[gamemode]
script = "gamemodes/freeroam.lua" # everyone in one world around the spawn, global chat, parties, the NPC actor demo
# script = "gamemodes/basicrp.lua" # role-play on your own database: accounts, characters kept, local chat - needs [gamemode.database]
# script = "gamemodes/duel_arena.lua" # /duel queues you; two at a time fight in the arena, nobody else can be hurt
# script = "gamemodes/marker/marker.lua" # the example with a client half: a checkpoint run drawn in each player's game
# script = "gamemodes/arena/Arena.dll" # a C# plugin, in a folder of its own
# script = "" # the built-in freeroam
watch = false # true: a changed script is reloaded by itself (a development server)

A mode is reloaded without a restart by /reload in the chat (admins), by the mode itself, or by watch = true whenever its file changes on disk.

  • In Lua: a file next to the shipped modes, named in server.toml. Getting started on the server is the first script, the tick, ids and units and what happens on an error; the Server API index has every callback and function. A mode that wants something on the players’ screens adds a client script in a client/ folder next to itself.
  • In C#: a class library compiled against sdk/KcdMp.Api.dll, published into a folder of its own under gamemodes/. The C# server API has the project file, the loading, a database behind a plugin and every interface. A C# mode’s client half is a Lua client script all the same.

Whichever it is, the mode runs on the server’s simulation thread, one tick at a time, 30 times a second: a slow callback stalls every player, and the server log says so when it happens.

The server’s own commands - /give, /tp, /horse, /time, /weather, /kick, /reload, /objectinfo and the rest - answer admins only, and admins are the game mode’s to name: the server keeps no accounts and no admin list, and remembers nothing about a player between visits. The shipped freeroam mode promotes the names of the KCDMP_ADMINS environment variable, so on the machine that runs the server:

KCDMP_ADMINS=Henry,Hans

A mode of your own promotes whoever it likes with SetPlayerAdmin - from a list in the script, or from its own accounts. Accounts (a /register and a /login, a player put back where they left, factions, scores) are what a mode builds on a database of its own once you connect one: [gamemode.database] in server.toml, MySQL / MariaDB or PostgreSQL, the databases guide. Without one the freeroam’s /register says this server keeps no accounts, and everything else works as before. Chat commands lists every built-in and who may use it.

The server folder carries the whole API in the two forms editors read, so completion, documentation on hover and a warning for a wrong name or argument are there before the server ever runs a line:

  • Lua - sdk/KcdMp.d.lua (the game mode API) and sdk/KcdMp-client.d.lua (the client script API) are definitions for the Lua language server (LuaLS). In VS Code install the “Lua” extension (sumneko) and open the gamemodes folder: its .luarc.json already points the language server at ../sdk. Any other editor that runs the Lua language server takes the same file. For a mode in a folder of its own, put a .luarc.json next to the script:

    { "runtime.version": "Lua 5.4", "workspace.library": ["../../sdk"], "workspace.checkThirdParty": false }

    or copy the .d.lua file into the folder and point workspace.library at ".". lua-language-server --check . in that folder is the same check from a terminal: an unknown name or a wrong argument type is a diagnostic there and a silent nil on the server. The files are also downloadable from this site: KcdMp.d.lua, KcdMp-client.d.lua.

  • C# - sdk/KcdMp.Api.dll with KcdMp.Api.xml next to it: a project that references the DLL gets IntelliSense with every member’s description in Visual Studio, Rider or VS Code with the C# extension. The project file is on the C# page.

The same files are what a coding assistant reads: AI assistants says how to give one the whole reference.