Multiplayer & Networking
Client-Server Architecture
Each client is connected to the server. The server receives information and then sends it to clients when needed. This allows you to see other players moving around for example.
KrunkScript separates logic into two execution contexts:
- Client (client) - Runs in the player's browser. Handles rendering, UI, inputs, and local game state
- Server (server) - Runs on the game server. Handles authoritative game state, scoring, and player management
The server should always have authority over important game state. Never trust the client for authoritative logic like scoring, health, or item ownership.
Sending Data
To send information from the client to the server:
# client-side: send network message to server
GAME.NETWORK.send(
"test", # str message key
{a: 1} # obj data to send
);
The server has multiple ways to send data to clients:
# server-side: send network message to specific client
GAME.NETWORK.send(
"test", # str message key
{a: 1}, # obj data to send
(str) player.id # str player id to send data to
);
# server-side: send network message to all clients
GAME.NETWORK.broadcast(
"test", # str message key
{a: 1} # obj data to send
);
Receiving Data
Both the client and server scripts have built-in hooks that receive network messages.
Server-side - receives data from clients. The playerID tells you who sent it:
public action onNetworkMessage(str id, obj data, str playerID) {
# id is the unique id of the network message
# data contains custom data from the client
# playerID is the unique ID of the player that sent it
if (id == "test") {
GAME.log((num) data.x); # access property
};
}
Client-side - receives data from the server:
public action onNetworkMessage(str id, obj data) {
# id is the unique id of the network message
# data contains custom data from the server
if (id == "test") {
GAME.log((num) data.x); # access property
};
}
Rate Limiting
Network messages are rate limited. You can detect if you have hit the limit:
# server-side: check for success
if (GAME.NETWORK.broadcast("hi there", {a: 1})) {
# message was sent
} else {
# message was rate limited
}
Network Performance
It is important to consider networking performance when sending data. The more frequently you send data, the higher the impact on performance. Send as little data as possible:
# BAD: too much data
GAME.NETWORK.send("myNetworkMessage", {
valueName: "test",
longNumber: 1020.925827
});
# GOOD: minimal data with short keys
GAME.NETWORK.send("1", {
t: "test",
n: Math.round(1020.925827) # round value
});
In short: less data sent less frequently is better for your performance.
Syncing Objects
When synchronizing an object's position in a multiplayer environment, the server should have authority. For example, to have a cube that moves for all players:
- Update the object position on the server
- Broadcast position changes to clients at a fixed rate
- On the client, apply the received position
Network Limits
| Limit | Value |
|---|---|
| Message ID length | 10 characters |
| Data size | 2000 bytes |
| Broadcast (server to all) | 10 msg/sec |
| Send (server to client) | 20 msg/sec per user |
| Send (client to server) | 40 msg/sec |
If you run into issues with these limitations, restructure your data and logic to send less data less frequently.