Getting Started

Welcome to the King Arthur’s Gold community-driven documentation!

This documentation aims to cover the scripting API exposed by the Crismon Engine used by KAG, documentation over KAG scripts. It also aims to cover the REST API which allows getting information over players and servers, and others features such as TCPR.

Please do note that this documentation is under heavy work. It is therefore not complete and some information might be false.
In the mean time, you can help contribute or refer to the Manual folder in KAG and to the official online documentation.

KAG uses AngelScript 2.27.1 as a scripting language. You may find documentation for it here.

Contributing

You can find tips about contributing to this documentation on the Github repository.

CBlob

The 'entity' class of the engine.

CBlob is the basic entity type. Blobs can be created using server_CreateBlob, but cannot be constructed directly, and so is only accessed through a handle.
CBlob can hold various classes required for creating an entity in the game, including shapes, a sprite, etc. and can be bound to a CPlayer.

CBlob::getAngleDegrees

Get the blob angle in degrees

  float getAngleDegrees()

CBlob::setAngleDegrees

Set the blob angle in degrees

float angle
The angle in degrees to apply to the blob.

The angle can still be set though the CShape rotations are disabled (through CShape::SetRotationsAllowed).

This function has to be called client-side as well when handling player blobs, otherwise only other players will see the sprite rotated.

A positive angle value will rotate the blob clockwise.

  void setAngleDegrees(float angle)

CShape::RemoveShape

Remove a shape

int index
The index of the shape to remove. The base shape has index 0.

Removing a shape that doesn’t exist might cause an engine crash.
Removing the base shape might cause an engine crash.
CShape::AddShape doesn’t seem to behave instantly, so you might need to wait at least next tick before removing a shape that was just added. Link
Furthermore, removing a shape might have side-effects later, such as the deleted shape reappearing. Link
For those reasons, this function should not be used.

  void RemoveShape(int index)

TCPR - Getting Started

TCPR is the standard way to administrate a KAG server remotely through TCP. Its usage is similar to that of RCON, accessed from the /rcon command in KAG’s built-in console (home key).
Because of its nature, it’s easy to use in nearly every language. This documentation will provide an example application in Python, but it is doable (with external libraries) in C++, Java, C#…

You can find an (outdated) documentation of TCPR on the KAG Wiki.
KAG build 1591(?) came up with overhauled TCPR with more capabilities (such as now being Windows-compatible) and build 1865 came up with a TCPR maximal line size change.

sv_tcpr has to be set to 1 for TCPR to be enabled. Then, set sv_rconpassword to the password of your choice (which can be used both to login with TCPR and over RCON). The 50301 port has to be forwarded for TCP (whereas the game itself uses UDP over 50301 as well) to connect from another machine.

The TCPR protocol

TCPR is a simple TCP protocol. Messages between the TCPR client and server are plain text.

To auth, you have to send the RCON password in plain text (as defined by sv_rconpassword) terminated by a newline. When the wrong password is entered, the connection is closed.

The TCPR server will determine the newline type depending on what you sent during auth. For example, you can use the newline character \n as well as \r\n (CRLF) during auth. The setting will then be used for the rest of the session.

Messages are generally prefixed by the current time, in the [HH:MM:SS] format.

The TCPR server will split lines longer than ~16k bytes.
This limit might be extended in the future, but don’t send that much data all at once.

Because TCP is stream-based, your network library sometimes will return you a packet that does not contain an entire TCPR message or that contains more than one. To avoid this, you should read TCPR messages until your newline character.

Commands works the same way as from the ingame console. You can send commands terminated by your newline. KAG built-in commands are prefixed by a slash / character. To send AngelScript code, omit the slash. You may get a list of commands using /help or /list. autoconfig variables are exposed as commands and as global AngelScript variables.

/rcon is only required when using the ingame console.

The doublequote " character is broken in the ingame console, but works through TCPR.

Script tcpr() allows to send messages exclusively to TCPR clients, but not to logs.
sv_print_tcpr_specific logs tcpr()-sent messages.
sv_tcpr_everything hides non-TCPR messages from TCPR clients, in which case only messages sent by tcpr() and some messages (such as the server shutting down) will be received by TCPR clients.

Using TCPR with Python 3

In order to use TCP sockets in Python, you will need to import the socket library.
This script will read chat and console logs from TCPR. It will print to the logs whenever a chat message is detected, and if the chat message is ‘!help’, it will broadcast a message. The first argument passed to the script will be the ip address and the second argument will be the port to connect to, and read the password from the standard input.

#!/usr/bin/python

import socket
import sys
import re # Regular expression

# Read from the socket until the newline character.
# Unfortunately python sockets doesn't have a simple feature for that.
def readUntilNewline(sock, rest):
	# Get the rest data from the last read, splitted over '\n'.
	# So if there is more than one element in rest, we have a line ready.
	if len(rest) >= 2:
		# Tuple, first element is the requested line, second is the rest
		return (rest[0], rest[1:])

	# ... in the other case use it as the beginning of the line to read
	chunkList = rest

	# Read chunks of data
	while True:
		# Receive a data chunk
		data = sock.recv(1024).decode()

		if not data:
			raise EOFError("Socket closed")

		chunkList.append(data)
		tokenized = data.split("\n")

		# We found a '\n' character: return the user the line he wants and the rest data
		if "\n" in data:
			# Get every chunk but the last one and add the first part of the latest chunk manually.
			return ("".join(chunkList[:-1]) + tokenized[0], tokenized[1:])

# Beginning of the script
if len(sys.argv) <= 2:
	print("Usage: tcpr.py [server] [port]")
	sys.exit()

sock = socket.socket()

try:
	sock.connect((sys.argv[1], int(sys.argv[2])))
except ConnectionError:
	print("[TCPR] Connection error")
	sys.exit()

pwd = input("[TCPR] Enter password: ")
sock.send((pwd + "\n").encode())

sock.send("/msg Hello from Python!\n".encode())

rest = []
try:
	while True:
		line, rest = readUntilNewline(sock, rest)

		# Regular expression search: look up for the chat messages exclusively
		chatResult = re.search("\[\d{2}:\d{2}:\d{2}\] \<(.*)\> (.*)", line)

		# If the message is really a chat message
		if chatResult is not None:
			chatSender = chatResult.group(1)
			chatMessage = chatResult.group(2)

			print("[App] Received chat message from '", chatSender, "': '", chatMessage, "'", sep="")

			if chatMessage == "!help":
				sock.send(("/msg Hi, " + chatSender + ", welcome to this server! Some useful info: ...\n").encode())

		print("[Server]", line)
# Connection lost to the server
except EOFError:
	print("[TCPR] Connection lost.")

Example usage: python tcpr.py localhost 50301

You should receive player messages along with other servers logs, including TCPR feedback:

[App] Received chat message from 'FIST! Asu': '!hello'
[Server] [15:28:09] <FIST! Asu> !hello
[Server] [15:28:10] Config file not found 'help'
[Server] [15:28:10] Loading blob config from help...
[Server] [15:28:10] ERROR: Blob config not found... help
[App] Received chat message from 'FIST! Asu': '!help'
[Server] [15:28:10] <FIST! Asu> !help
[Server] [15:28:10] RCON command from 127.0.0.1:17576 :
[Server] [15:28:10] /msg Hi, FIST! Asu, welcome to this server! Some useful info: ...
[Server] [15:28:10]