net

Outgoing TCP, for talking to a program that listens on a port: LiveSplit's server, a stream tool, something on another PC. Nothing connects until the user says so. The first time your mod tries an address, the engine asks the user in a window of its own: Allow, Disallow, or Uninstall mod (after two Disallows, also Block all network for this mod). The answer is remembered for your mod, that address and that port. Another port, another address or another mod is asked about separately. The user can take any answer back in Options → Network.

Connect only. There is no listening and no UDP, so nothing on the network can reach your mod first. Workers have no net.

None of it runs on the frame loop. The engine's own network thread connects, sends, reads, and asks your questions on a timer (conn:watch), and your mod hears about it through onState and onReceive only when something actually happened. A program on the other end that is slow to answer slows down nothing.

functionnet.connect(host, port) → Connection | nil, why

Starts a connection and returns it at once. It never waits: the connection reads "asking" while the user decides and "connecting" until the other side answers. Set onState to be told when that changes. Returns nil and a sentence only when the arguments are not a host and a port. Every other outcome (refused, blocked, too many) is a connection whose state says so.

ParamTypeNotes
hoststringAn address ("127.0.0.1", "::1") or a name ("localhost"). A name is looked up once, off the main thread. The user is asked about the address it resolved to, and the connection goes to that address, so a name pointed somewhere else later cannot take the user's yes with it.
portinteger1 to 65535.

One question at a time. While the user is being asked about one address for your mod, a try at a different address is turned away on the spot (state "denied", nothing remembered). Try it again once the first is answered. Another try at the same address waits on the same answer.

Limits, per mod: 8 connections at once, 5 connects a second, 1 MB waiting to be sent and 1 MB waiting to be read. A connect that has not finished after 5 seconds fails.

local ls = net.connect("127.0.0.1", 16834)    -- LiveSplit Server's default

ls:onState(function(state, why)
    if state == "open" then
        -- Asked four times a second by the engine; you hear only changes.
        ls:watch("getcurrentsplitindex\r\n", 250)
    end
end)
ls:onReceive(function(data)
    print("LiveSplit is now on", data)
end)

-- Later, whenever it is time:
ls:send("split\r\n")
methodconn:state() → string

One of:

StateMeaning
"resolving"Looking up the name.
"asking"Waiting for the user's answer.
"connecting"Allowed, and waiting for the other side.
"open"Connected. Bytes go both ways.
"closed"Closed by you, by the other side, or by the user taking the permission back. What the other side sent last can still be read.
"failed"Could not connect, or broke. error() says why.
"denied"The user said no, blocked your mod, or was still being asked about another address.
methodconn:send(data) → ok, why

Hands the bytes to the engine's network thread, which sends them at once. You may send before the connection is open: the bytes wait and go out once it opens, or are dropped if it never does. Returns false and why once the connection is closed, failed or denied, or when more than 1 MB is already waiting.

ParamTypeNotes
datastringSent as-is. Add your own line ending if the other side expects one (LiveSplit wants \r\n).
methodconn:onReceive(fn)

Calls fn(data) with what arrived, when something arrives, and never otherwise. TCP is a stream, not messages: a reply can arrive in pieces or two at once, so collect until you see your delimiter. While it is set, what arrives goes to it and not to receive(). nil removes it.

methodconn:onState(fn)

Calls fn(state, why) when the state changes, and once straight away with the state it is in now, so a connection that was already refused is still reported. why is what error() would say, or nil. nil removes it.

Both callbacks run on the frame loop, between frames, like everything else in your mod. A function that uses its connection keeps it alive; close() lets go of both callbacks.

methodconn:watch(text, everyMs) → ok, why

For a program that has to be asked what changed, as LiveSplit does. The engine sends text every everyMs on its own clock, reads the answers itself, and passes a line on to onReceive only when it differs from the line before it. Your mod is not called at all while the answer stays the same. The first answer of a new watch always comes through. Call it again to change it, or with nil to stop.

ParamTypeNotes
textstring | nilSent as-is, at most 4096 bytes. nil or "" stops it.
everyMsnumberAt least 20. The first one goes at once, or the moment the connection opens.

Lines are split at \n and compared whole, so the program's answers have to be one per line. What you send yourself in between is answered on the same stream; a different line comes through, the same one does not.

methodconn:repeat(text, everyMs) → ok, why

Like watch, but every answer comes through: for a keep-alive, or when you need each reply. One per connection, shared with watch; the newest call wins.

methodconn:receive() → string

Everything that has arrived since the last call, or "", for a mod that would rather look than be told. Not needed with onReceive.

methodconn:error() → string | nil

Why the connection is closed, failed or denied, in a sentence. nil while nothing went wrong.

methodconn:close()

Closes it. A connection you drop all references to is closed when the collector takes it, and all of your mod's connections close when it is unloaded.

What the user sees: the question, drawn by the engine over everything. Your panels cannot cover it, nothing they click goes through to it, and no key press reaches any mod while it is up. Its buttons ignore clicks for the first moment it is shown, so a question that appears just as the user clicks something else cannot take that click. While any mod holds a connection, a Connected badge shows in the corner: always with the overlay open, and for a few seconds whenever a new connection opens with it closed.
One page of the MCCP modding reference. Every section is its own document; search covers all of them.