KKL Control Protocol

How to make a local server for Kisekae that the Character Editor can use


Starting from version v100.2, KKL comes with an optional built-in TCP server allowing for remote control of a running KKL instance.

Note

This guide is intended for SPNatI coders. Those just interested in character development do not need to be concerned with this guide. Even the guy who organized these docs doesn't understand a lick of it.

Enabling the server

The remote-control server is disabled by default; on startup, KKL.exe will look for a file named enable_server in the same directory as itself.

If this file exists, KKL will attempt to bind to port 8008 on 127.0.0.1. If it fails to bind to the port, the server will silently disable itself for that session.

Reference Client

A reference protocol client library written in Python 3 can be found alongside this document.

Here's an example of how to use it:

import asyncio
import sys

from kkl_client import KisekaeLocalClient, KisekaeServerRequest

async def main():
    # Read a Kisekae code from a file specified on the command line:
    with open(sys.argv[2], "r", encoding="utf-8") as in_file:
        code = in_file.read()

    # Connect to the local KKL instance.
    # Try to connect five times before giving up.
    client = await KisekaeLocalClient.connect(5)

    # Run the loop for reading server responses in a parallel Task.
    asyncio.create_task(client.run())

    # Prepare our import request.
    request = KisekaeServerRequest.import_full(code)

    # Send our request to the server.
    resp = await client.send_command(request)

    if resp.is_success():
        # Our import succeeded.
        image_data = resp.get_data()

        # Write the received image data to a file specified on command line.
        with open(sys.argv[2], "wb") as out_file:
            out_file.write(image_data)

        print("Code successfully converted.")
    else:
        # There was an error.
        print("Server reported error: " + resp.get_reason())

asyncio.run(main())

It can also be used directly to interact with local KKL instances from the command-line:

python3 kkl_client.py import-full [in_file] [out_file]

Protocol Overview

Note: a reference protocol client implementation (in Python) can be found alongside this document.

In the following documentation, the server refers to the KKL instance.

All messages transmitted between client and server begin with the following 9-byte header:

Offset Length Data Description
0 4 Protocol header "KKL " (note the trailing space), in ASCII / UTF-8
4 1 Message type See below
5 4 Payload data length Does not include header data

Message Types

Byte Value Message Type Sent By Description
0x01 Command Client Instructs the server KKL instance to perform some action.
0x02 Cmd. Response Server Sent by the server in response to a Command message. The server will send multiple response packets for a given command.
0x03 Image Data Server Contains the final output image generated by an Import or Screenshot command.
0x04 Heartbeat Server The server will send these roughly every 5 seconds after establishing a connection with a client.

Command Messages

The payload of a Command message is a UTF-8 string containing a JSON-serialized object.

The following fields are common to all Command types:

Field Name Data Type Description
type string The command to issue to KKL. See below for info on each command.
id number, optional Will not affect processing on its own, but the server will attach it to all outgoing messages related to this request.

The following is a quick overview of currently implemented Command types and their parameters:

Command type Field Values Parameters
Version version None
Full Import import code
Partial Import import_partial code
Screenshot screenshot bg
Reset reset_full, reset_partial None
Peek/Poke character_data character, op, tabName, tabParameter, value, internalNames
Set Alpha alpha_direct character, op, path, value, multiplier
Set Alpha (testing) alpha character, colorIndex, part, alpha
Dump Character dump_character character
Fastload fastload character, data, attachments, version, read_from_cache, write_to_cache
Optimized Screenshot direct-screenshot bg, size, shift, scale, fastEncode

Version Command

This command retrieves the major and minor version of the remote KKL server. The data field of the server response will be a subobject; the server version numbers will be within the major and minor fields of this subobject.

Full and Partial Import Commands

These commands instruct KKL to import a code into the Kisekae workspace. A "full import" will additionally take a screenshot immediately afterwards, similarly to the traditional file-based image export flow.

A full import command will return its response as an Image Data message (type 0x03), however a partial import command will use a regular Command Response message to report completion.

The code to import must be specified as a string-valued code field within the Command object. For the full Import command (that takes screenshots), alpha parameters can be prepended to the code just as in regular file-based imports. (Alpha parameters aren't supported for partial imports yet.)

Screenshot Command

Screenshot commands take a screenshot of the Kisekae workspace.

A boolean bg parameter can be passed as an optional field within the Command object; if true, then the scene background will be included within the returned image. By default, scene backgrounds will not be included in screenshots.

This command will always return its response as an Image Data message (type 0x03).

Reset Commands

Reset commands instruct KKL to reset the scene prop, background, and camera settings. A "full" reset will also hide all but the first character in the Kisekae lineup. This is useful for making standard pose images.

Peek / Poke (aka Character Data) Commands

These commands can be used to directly inspect and modify the data of characters within the Kisekae workspace.

Parameter Data Type Description
character number The zero-based index of the character to inspect or modify. Valid range is 0-8, inclusive.
op string Either get or set.
tabName string The name of the data group (or "tab") to inspect / modify.
tabParameter string or number The numeric index or internal name of the parameter within the group to inspect / modify.
value number / boolean / string If op == set, then this is the value that the named parameter will be set to.
internalNames boolean, optional If true, then tabName and tabParameter will be interpreted as direct string keys within the Kisekae-internal charaData structure. (not recommended)

When internalNames is false (the default), tabName as the prefix for an import/export data group, and tabParameter is interpreted as an index within that data group.

For example, consider the following Kisekae code fragment (containing information related to character positioning):

100**bc410.500.0.0.1.0

The prefix for this data group is bc, and the elements within the group are [410, 500, 0, 0, 1, 0].

The element at index 4 corresponds to the flag controlling the visibility of the character's shadow. Therefore, if we wanted to determine whether the first loaded character's shadow was visible or not, we could issue the command:

{
    "type": "character_data",
    "op": "get",
    "character": 0,
    "tabName": "bc",
    "tabParameter": 4
}

If we wanted to disable that same character's shadow without using the Import command or having to resort to Kisekae code manipulation, we can issue the command:

{
    "type": "character_data",
    "op": "set",
    "character": 0,
    "tabName": "bc",
    "tabParameter": 4,
    "value": false
}

The same command could also be used to enable the character's shadow, by setting the value field to true.

Part Transparency Control Commands

Parameter Data Type Description
character number The index of the character to inspect or modify. Valid range is 0-8, inclusive. Ignored for reset_all ops.
op string Either get, set, reset, or reset_all.
path string The sprite to inspect or modify; see the Alpha Transparency documentation for example values. Ignored for reset_all ops.
value integer (0-255) If op == set, then this is the alpha value the part will use. Ignored for get, reset, and reset_all ops.
multiplier float (0-1), default 0 A multiplier value that allows for controlled mixing of parent part alpha values. Doesn't seem to have much of an effect?

These commands can be used to get and set part transparency for characters in the Kisekae workspace, using the same mechanisms as the alpha value settings that can be attached to import requests.

Issuing a set operation will change the alpha transparency for a part, and a reset operation will clear any transparency changes made to it in turn. A reset_all operation will reset all alpha transparency settings to their defaults, across all characters.

get operations can be used to probe alpha transparency settings for parts; within the returned data object, the alpha and multiplier fields will list the queried part's alpha channel value and alpha transform multiplier. For parts that have had custom transparency set, this corresponds to the value and multiplier command fields, respectively. For parts that have not had custom transparency set, value is usually equal to 0 and multiplier is usually 1.0, though this is not guaranteed.

For example, to hide the first character's left foot, we can issue the command:

{
    "type": "alpha_direct",
    "op": "set",
    "character": 0,
    "path": "ashi0.foot.foot",
    "value": 0
}

We can subsequently reset it by issuing the command:

{
    "type": "alpha_direct",
    "op": "reset",
    "character": 0,
    "path": "ashi0.foot.foot",
}

Experimental Transparency Control

(documentation coming soon)

Dump Character Command

This command dumps the entire internal character data structure for the given character within the Kisekae workspace and returns it as the response data.

This command is relatively fast, but produces a lot of output.

Fast Load Character Data

Added in version 104.1.

This command loads character data into the Kisekae workspace using an optimized procedure that attempts to minimize the amount of graphical updates and other processing performed, compared to a full import cycle.

The only two required parameters for this command are data and character.

The character parameter should be the zero-based index of the character to load data into.

The request data should be a list containing three-element lists of [subcode_prefix, subcode_index, value], with one list for each model parameter to change.

For example, the Kisekae code fragment aa26.290.0.0 could be represented this way as:

[
    ["aa", 0, "26"],
    ["aa", 1, "290"],
    ["aa", 2, "0"],
    ["aa", 3, "0"]
]

Data values may be either strings or other values of appropriate types, depending on the parameter. Sending values as they appear in save codes should always work, regardless of parameter type.

The attachments parameter, if provided, should be a dictionary mapping updated image attachment slots to their image paths. For example:

{
    "0": "images/attachment.png"
}

The version parameter should be the version of the Kisekae instance that generated the provided data. If you are sending data from a Kisekae code, this should be the version number attached to the code. This parameter is used to apply version-specific compatibility updates to the incoming data. If this is not provided, it is assumed to be the server's Kisekae version.

read_from_cache and write_to_cache can be used to control server-side caching of data sent via this command. By default, data loaded via this command will be saved to a per-character cache, so that redundant parameter updates can be identified and skipped.

This can potentially save a massive amount of time in cases where many data loads are performed in sequence. However, if there are unforeseen bugs resulting in false-positive cache matches, this could result in issues loading data (i.e. parameter updates being skipped that shouldn't be). In this case, read_from_cache can be set to false to force KKL to bypass the cache and always apply sent updates.

If not provided, both read_from_cache and write_to_cache are assumed to be true.

Note that the cache for a character is always invalidated when the user makes manual changes to them in the Kisekae workspace.

Optimized Screenshot Command

Added in version 104.1.

The direct-screenshot command works like the regular screenshot command, but provides more options and is also better optimized.

This command's default settings specifically emulate standard SPNATI screenshot settings, as set by the reset-full command.

The scale parameter controls the resolution of output images, relative to the default internal stage size of 800x600 pixels; this parameter's default value of 2.5 corresponds to the maximum quality value provided by Kisekae.

The size parameter, if set, must be a list of two numbers, and will override the default output image size computed with scale. The area captured by the screenshot will be automatically shifted so that the subject area remains centered (modulo the effect of any shift parameter, below).

The shift parameter, if set, must also be a list of two numbers, which can be used to shift the subject area captured by the screenshot. Positive values for X and Y correspond to shifts to the right and down, respectively.

The bg parameter can be used to control whether the scene background will be included in the returned image.

Finally, the fastEncode parameter, if set to true, changes the PNG encoder settings for the image to be faster, but less space-efficient.

On my machine, "fastEncode": true brings the time required to take a screenshot down from roughly 2.12 seconds to about 0.17 seconds. However, the resulting images are about 1.4x to 1.6x larger; this may not be a problem if you're performing processing that would require re-encoding anyways, or if you're going to re-compress the images with external tools.

This command will always return its response as an Image Data message (type 0x03).

Command Response Messages

The payload of a Command Response message is also a UTF-8 string containing a JSON-serialized object. These objects have the following schema:

{
    "status": "in_progress" | "done" | "error",
    "id": number (optional),
    "data": <any type>,
    "reason": string (only if status == "error"),
}

The "id" parameter indicates what request this response corresponds to; if the original request had no associated "id", then it will be set to 0.

Upon receiving a request, the server will first send a response with "status": "in_progress" to indicate that it has received the request.

Once a given request is complete, the server will send another response with "status": "done" or "status": "error" as appropriate. Commands that return image data (such as Full Import or Screenshot commands) will instead return an Image Data message on successful completion.

For responses with "status": "error", a reason string will also be provided with a human-friendly description of the error.

For commands that return some kind of data response, the data field will contain that information for successful responses.

Image Data Messages

Success for Import commands is indicated via an Image Data message, which contains the following data:

Offset Length Data Description
9 4 Identifier The "id" parameter sent with the original request.
13 Variable Image data This is the PNG-encoded data that KKL would normally write to a file after importing.

Heartbeat Messages

The server will send heartbeat messages to all connected clients roughly every five seconds (though KKL lag and runtime freezes may cause heartbeats to be delayed).

Heartbeat messages have no payload and have a payload data length of 0.