- More HTTPS API endpoints: https://gist.github.com/dzhu/d6999d126d0182973b5c
- Some js websocket code and stuff: https://gist.github.com/NhanHo/87c679ca456c83185b82
Screeps uses the sockjs API (https://github.com/sockjs/sockjs-client/blob/master/lib/main.js) for websocket communications. A brief summary of the low-level protocol:
- The websocket endpoint is
wss://screeps.com/socket/[arbitrary 3digit number]/[arbitrary 8char string]/websocket
. - Incoming messages always have a type (character 0) followed by an optional JSON-encoded payload (everything else).
- Incoming
o
is aopen
message, meaning the remote end is ready to listen. - Incoming
h
is aheartbeat
message, meaning the remote end is still listening. - Incoming
c
with a JSON-encoded array is aclose
message.payload[0]
is a code (number).payload[1]
is a reason (probably human readable string).
- Incoming
m
with a JSON-encoded object is a single payload message. - Incoming
a
with a JSON-encoded array is a batch payload message; interpret every array element as a separate message.- Individual JSON payloads are presented as strings. You have to deserialize the payload, then any subpayloads separately.
- Incoming
- Outgoing messages are sent as quoted escaped strings encased in square brackets
(e.g.
["hello world"]
).
POST to https://screeps.com/api/auth/signin
with a JSON object payload.
{
"email": "YOUR_EMAIL",
"password": "YOUR_PASSWORD"
}
This returns a JSON object:
{
"ok": 1,
"token": "YOUR_SESSION_TOKEN"
}
If you get a 401 Unauthorized
your email or password is wrong.
GET from https://screeps.com/api/auth/me
with a header X-Token: YOUR_SESSION_TOKEN
and X-Username: YOUR_SESSION_TOKEN
.
This returns a JSON object:
{
"_id": "YOUR_PLAYER_ID",
"badge": {
"type": int,
"color1": int,
"color2": int,
"color3": int,
"param": int,
"flip": bool
},
"cpu": YOUR_CPU,
"credits": YOUR_CPU_CREDITS,
"email": "YOUR_EMAIL",
"gcl": YOUR_GCL_POINTS,
"github": {
"id": "string",
"username": "string"
},
"lastChargeTime": YOUR_LAST_CHARGE_TIME,
"notifyPrefs": {
"errorsInterval": int,
"sendOnline": bool
},
"ok": 1,
"password": true,
"username": "YOUR_USERNAME"
}
This also returns a response header X-Token: YOUR_SESSION_TOKEN
with which you should
overwrite your current session token.
This is sent by the remote end at session start.
Remote: "time TIME"
TIME
: the current time in milliseconds since the Unix epoch.
WebSocket auth YOUR_SESSION_TOKEN
.
If your session token is good then you'll receive back a reply:
Remote: "auth ok YOUR_SESSION_TOKEN"
with which you should update your session token.
Otherwise you'll receive:
Remote: "auth failed"
WebSocket subscribe STREAM_NAME
.
Afterwards you'll get publish updates of the form
Remote [JSON]: ["STREAM_NAME", STREAM_PAYLOAD]
with the STREAM_PAYLOAD
depending on the stream.
To stop the stream:
WebSocket unsubscribe STREAM_NAME
.
Stream user:YOUR_PLAYER_ID/cpu
.
Payload:
{
"cpu": LAST_CPU_MS,
"memory": LAST_MEMORY_BYTES
}
GET https://screeps.com/api/game/room-terrain?room=ROOM_NAME
(no auth).
Payload:
{
"ok": 1,
"terrain": [
...
{
"room": "ROOM_NAME",
"x": int,
"y": int,
"type": "wall | swamp"
}
...
]
}
Any square not listed can be assumed "plain".
GET https://screeps.com/api/game/room-terrain?room=ROOM_NAME&encoded=true
(no auth).
Payload:
{
"ok": 1,
"terrain": [
{
"_id": "SOME_ID",
"room": "ROOM_NAME",
"terrain": "TERRAIN_DATA",
"type": "terrain"
}
]
}
SOME_ID
might be the room ID, I'm not sure.
TERRAIN_DATA
is the serialized terrain data, left-to-right, top-to-bottom:
0
: plain1
: wall2
: swamp3
: wall (?)
Stream roomMap2:ROOM_NAME
.
Payload:
{
"walls": [
...
[x, y],
...
],
"roads": [
...
[x, y],
...
],
"SOME_PLAYER_ID": [
...
[x, y],
...
],
...
}
The payload describes the current locations of all constructed walls, roads, and any player-owned stuff in the target room.
Stream room:ROOM_NAME
.
Payload:
{
"objects": {
...
"OBJECT_ID": {
"id": "OBJECT_ID",
"type": "OBJECT_TYPE",
"x": int,
"y": int,
...
},
...
},
"users": {
...
"USER_ID": {
"_id": "USER_ID",
"username": "USERNAME",
"badge": {
"type": int,
"color1": int,
"color2": int,
"color3": int,
"param": int,
"flip": bool
}
},
...
},
"info": {
"mode": "world"
},
"gameTime": GAME_TICK_NUM
}
The first such message after subscribing contains the entire world state. Subsequent messages contain only changed values.
If in objects
an OBJECT_ID
resolves to null
then that object no longer
exists and must be removed from the world state.
Members of objects
can have different members depending on their type.
Some of these are familiar. Some of these are not.
Stream user:USER_ID/console
.
Payload:
{
"messages": {
"log": [
...
"LOG_LINE_TEXT",
...
],
"results": [
...
"RESULTS_LINE_TEXT",
...
]
}
}
Payload on console error:
{
"error": "ERROR_STRING"
}
POST https://screeps.com/api/user/console
:
{
"expression": "YOUR_CONSOLE_EXPRESSION"
}
Returns on success:
{
"ok": 1,
"insertedCount": 1,
"ops": [
{
"user": "YOUR_PLAYER_ID",
"expression": "YOUR_CONSOLE_EXPRESSION",
"_id": "OPERATION_ID"
}
],
"insertedCount": 1,
"insertedIds": ["OPERATION_ID"]
}
The structure of the return suggests a way to post multiple console commands at once, but I don't know how to do this.
GET https://screeps.com/api/user/memory?path=MEMORY_PATH
MEMORY_PATH
is the path relative to the Memory root.
A blank MEMORY_PATH
retrieves all of memory.
Return payload:
{
"ok": 1,
"data": "gz:GZIPED_MEMORY_DATA"
}
Stream user:USER_ID/memory/MEMORY_PATH
.
Payload:
"thing as string"
This is almost always "[object Object]"
unless you're watching not an object.
So for interesting results you want to watch something that resolves to a
number or string or array of numbers / strings.
The terrain values are additive. 3 is "wall + swamp". I don't know when this would ever matter though, could just be their implementation leaking through.