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.