Skip to content

Instantly share code, notes, and snippets.

@bzy-xyz
Last active April 26, 2022 09:52
Show Gist options
  • Star 11 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save bzy-xyz/9c4d8c9f9498a2d7983d to your computer and use it in GitHub Desktop.
Save bzy-xyz/9c4d8c9f9498a2d7983d to your computer and use it in GitHub Desktop.
Description of the Screeps websocket API

Other sources of knowledge

Basics

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 a open message, meaning the remote end is ready to listen.
    • Incoming h is a heartbeat message, meaning the remote end is still listening.
    • Incoming c with a JSON-encoded array is a close 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.
  • Outgoing messages are sent as quoted escaped strings encased in square brackets (e.g. ["hello world"]).

Getting a session

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.

Getting your own user ID / info

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.

Getting the current time

This is sent by the remote end at session start.

Remote: "time TIME"

TIME: the current time in milliseconds since the Unix epoch.

Authenticating to the websocket

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"

Subscribing to various data streams

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.

Getting your current CPU consumption

Stream user:YOUR_PLAYER_ID/cpu.

Payload:

{
    "cpu": LAST_CPU_MS,
    "memory": LAST_MEMORY_BYTES
}

Getting basic terrain info

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".

Getting basic terrain info (serialized)

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: plain
  • 1: wall
  • 2: swamp
  • 3: wall (?)

Getting a basic map overlay (structures / creeps)

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.

Getting room details

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.

Getting the console feed

Stream user:USER_ID/console.

Payload:

{
    "messages": {
        "log": [
            ...
            "LOG_LINE_TEXT",
            ...
        ],
        "results": [
            ...
            "RESULTS_LINE_TEXT",
            ...
        ]
    }
}

Payload on console error:

{
    "error": "ERROR_STRING"
}

Sending a console command

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.

Retrieving a memory object

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"
}

Subscribing to a memory object

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.

@JoeRLDuncan
Copy link

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment