Resources
A resource is a folder in the server's resources folder with a package.json. Its scripts define your
server's commands, gamemodes, shops and anything else. You do not need to build the server or the mod, and
players download a resource's client part when they join.
For a step-by-step start, see Your first resource. The smallest working resource is two files:
{
"name": "hello",
"version": "1.0.0",
"kcds": {
"serverScripts": ["server.js"]
}
}const { Events, Chat } = kcds.core; Events.on('playerCommand', (player, command, args) => { if (command.toLowerCase() !== 'hello') { return; } Chat.sendToPlayer(player, args.length > 0 ? args.join(' ') : 'Hello!', { author: 'Server' }); });
The API is in the global kcds object and needs no import; start from the API overview. Commands
arrive without the slash, with arguments split at spaces. Case is kept, so do your own case-insensitive
comparison.
TypeScript
You can write in TypeScript if you compile it to CommonJS first and point the manifest at the compiled files.
Each release includes the SDK's declarations in KCDS-Types-<version>.zip. See TypeScript for
a project setup.
The manifest
KCDS reads the "kcds" section of package.json. A resource is identified by its name, not its folder.
| Key | Default | Meaning |
|---|---|---|
serverScripts | [] | server scripts (CommonJS), in the order they run |
clientScripts | [] | scripts each player's game runs; see Client resources |
sharedScripts | [] | scripts for both sides, run before that side's own list |
files (clientFiles) | [] | files sent to players but not run, such as pages, pictures and data |
loadingScreen | none | your page over joining and loading, sent first; see Web views |
exports | [] | names shared with other resources; see Imports and exports |
requires | [] | resources that must run first: names, or { "name": "x", "optional": true } |
errorBehavior | "stop" | what an uncaught error does: stop, restart (after one second) or continue |
priority | 0 | recorded, but does not change the start order |
File patterns
files takes relative paths with /, and patterns can use *, ?, **, [a-z] and *.{css,json}.
If files is empty, the folders of the client entry scripts are sent. With client.js next to package.json,
that is every file except the server entry scripts. Hidden files such as .env and .git, and node_modules,
are never sent that way.
A pattern matches hidden files only if it names the dot, but a broad one like ** does include node_modules.
Symbolic links are not followed.
Size limits
Each file sent to players can be up to 8 MB. A resource over a limit is not sent to players. The server logs
<name>: not sent to players: ..., its server scripts still run, and everything else carries on. If a refresh
pushes a resource over a limit, players keep the version they have.
What scripts can load
Both sides can require the resource's own .js, .cjs and .json files by relative path. Client scripts can
load nothing else.
Server scripts can also load:
- Node's modules, such as
node:fsandnode:path - packages in the resource's folder, after
npm install pgthere - all of the above through
globalThis.require, with relative paths from the resource's folder, which compiled code often uses
process.cwd() is the resource's folder, and a deployment replaces it. Save data under
kcds.core.Runtime.serverDir instead, the server's folder containing resources/ and server.json.
Network access from server scripts
Server scripts have fetch and WebSocket for things like a chat bot or a link to your services. When the
resource stops, its requests are aborted and its sockets closed. A resource can have up to 64 sockets open.
const socket = new WebSocket('wss://example.com/bot'); socket.addEventListener('open', () => socket.send(JSON.stringify({ hello: 'kcds' }))); socket.addEventListener('message', (event) => console.info(`bot says ${event.data}`));
Starting and stopping
Once a resource's scripts have run, all resources receive resourceStart(name), so compare the name with your
own.
KCDS waits for async handlers. Until the handler finishes, the resource is still starting and resources that require it wait. If it rejects or takes over 30 seconds, startup fails, and KCDS removes everything the resource registered.
When a resource stops, all resources first receive resourceStop(name), while the stopping one still works fully.
Its dependents stop before it. Async handlers get up to 10 seconds. Clean-up of handlers, timers, exports,
messages and anything it spawned always happens.
const { Events } = kcds.core; Events.on('resourceStart', async (name) => { if (name === 'hello') { console.info('hello is ready'); } }); Events.on('resourceStop', (name) => { if (name === 'hello') { console.info('saving before hello stops'); } });
Complete examples
The server comes with resources\freeroam and resources\dice, which show working server and client scripts.