Skip to content

Connections

A connection is the byte stream between the terminal and whatever drives it. The session sends the terminal’s output (query responses, mouse reports) to the connection, and feeds the connection’s incoming bytes to the emulator. The package ships five connections and an interface for your own.

The far end is Use
A host that speaks telnet: a MUD, a BBS, a login service TelnetConnection
A service that speaks plain lines over TCP, such as a MUD or a server of your own TcpConnection
A WebSocket relay in front of a pty, a serial port, or a host WebSocketConnection
A command line shared by ttyd TtydConnection
A program of yours in the same process LocalProgramConnection
Anything else: a pty or a serial port on the same machine Your own ITerminalConnection

A host that sends stray characters at connect, or never learns the window size, expects telnet; switch from TcpConnection to TelnetConnection.

Set a connection on the session, which opens it and disposes any previous one:

session.SetConnection(new TelnetConnection("host", 23));

SetConnection(null) detaches. A session needs no connection to show text; see Writing to the terminal yourself.

TelnetConnection speaks the telnet protocol over TCP: it negotiates options, reports the window size (NAWS) when the grid resizes, and answers the terminal type query with xterm-256color; set TerminalType before connecting to answer with another name. Use it for a login service or a MUD that expects telnet.

session.SetConnection(new TelnetConnection("your.mud", 4000));

TcpConnection is a raw byte stream, no negotiation. It suits a service that speaks plain lines: a MUD on a plain port, or a server of your own. Bytes go both ways as typed and as received, so a protocol with its own handshake, such as IRC’s PING and PONG, needs a program in front of it.

session.SetConnection(new TcpConnection("your.game.server", 4000));

WebSocketConnection treats each message from the server as bytes for the terminal, and sends each run of input as one binary message. It runs on every platform, WebGL included, where it is the way to reach a network host.

session.SetConnection(new WebSocketConnection("wss://relay.example.com/term"));

Set Subprotocols before connecting if the server expects one. A page served over HTTPS can only open wss:// addresses, and the server decides which pages may connect.

TtydConnection is a WebSocket connection to ttyd, which shares a command line program over a WebSocket. It reports the grid size when it connects and on every resize, so a full-screen program on the far end fills the terminal. Give it the address ending in /ws:

session.SetConnection(new TtydConnection("wss://relay.example.com/ws"));

Start ttyd with --writable, or it ignores input. Set AuthToken if the server was started with a credential.

To speak another relay’s framing, derive from WebSocketConnection and override OnConnected, HandleMessage, Send, and NotifyResize.

SetConnection returns at once. The connect, the reads, and the writes happen on background threads, and keys typed before the connect completes go out once it does. The session marshals every event to the main thread, so you do not handle threading yourself:

session.ConnectionOpened += () => status.text = "Connected";
session.ConnectionClosed += reason =>
status.text = reason.IsError ? $"Failed: {reason.Message}" : "Disconnected";

When the connection closes, the session also prints the reason into the terminal; turn off Print Close Reason to handle it yourself.

ITerminalProgram is a terminal program hosted inside the Unity process. It receives input bytes and resize events and writes ANSI back, the same contract a remote host has. LocalProgramConnection adapts it to the session.

public sealed class Greeter : ITerminalProgram
{
IProgramHost _host;
public void Start(IProgramHost host)
{
_host = host;
_host.Write("\x1b[2J\x1b[HHello. Press a key.\r\n");
}
public void OnInput(byte[] data) => _host.Write(data); // echo
public void OnResize(int cols, int rows) { }
public void Stop() { }
}
session.SetConnection(new LocalProgramConnection(new Greeter()));

This is how you build an in-game shell or console, or port an existing terminal program. Write the escape sequences the emulator understands (see Rendering and painting for the supported set), and read input as the bytes a terminal keyboard produces, or hand them to an AnsiInputDecoder to get keys, text, and mouse events. A program that also implements ITerminalTick is called every frame.

For a full-screen interface, see Interfaces, which also covers programs that draw cells directly and skip escape sequences.

IProgramHost.Exit() ends the program and closes the connection. The built-in DemoShell is an ITerminalProgram; read it for a worked example of line editing and command handling.

IProgramHost.Cols and Rows give the grid size, and OnResize reports each change. Lines end with \r\n.

DemoShell is the program Start Demo Shell runs. It also serves as a starting console: AddCommand adds a command of your own, which help then lists.

var shell = new DemoShell();
shell.AddCommand("restart", "restart the reactor", _ => reactor.Restart());
session.SetConnection(new LocalProgramConnection(shell));

Its telnet command opens a TelnetConnection inside the shell, and Ctrl-] returns to the prompt. Attach does the same with any connection, from a command of your own:

shell.AddCommand("uplink", "open the relay", _ => shell.Attach(new WebSocketConnection(url)));

RemoveCommand takes a command out of the shell and its help list, such as exit where the shell should stay. In a WebGL player the shell has no telnet command, since TcpConnection.IsSupported is false there. Set BannerFont to a FIGlet font to add the figlet command.

For output with nothing behind it, such as a boot sequence or a log a player only reads, write to the emulator:

session.Emulator.FeedText("\x1b[32mSYSTEM READY\x1b[0m\r\n");

Feed takes bytes and FeedText a string, escape sequences included. Call them on the main thread.

Implement ITerminalConnection to bridge to anything else: a serial port or a pty on desktop.

  • Return from Connect at once, then raise Connected when the stream opens.
  • Raise DataReceived with incoming bytes. Any thread will do; the session moves each event to the main thread.
  • Raise Closed once, with CloseReason.Ended for a close the far end asked for or CloseReason.Failed for an error.
  • Queue the terminal’s output in Send and return; do the write on a thread of your own.
  • Pass the grid size on in NotifyResize if the far end wants it.

To add a protocol on top of TCP, derive from TcpConnection and override HandleIncoming, as TelnetConnection does.

TcpConnection and TelnetConnection need sockets and threads, which a WebGL player lacks; TcpConnection.IsSupported says whether this platform has them. On WebGL, use WebSocketConnection, TtydConnection, LocalProgramConnection, or a connection of your own.

Themes and screen types covers the look.