subspace billing server protocol proposal version 1.22 grelminar@yahoo.com all communication goes over a single tcp socket. messages are lines, delimited by linefeed characters (ascii 10) (although servers and clients should accept CR, LF, and CRLF). fields within a message are delimited by colons (ascii 58). the first field is the type of the message. each type has a fixed number of fields to expect, so the last field can contain colons without confusing anything. integer values in fields should be in decimal. all lines will be no more than 1023 characters in length (including LF). either side may discard lines longer than that length if it receives them. the game server will initiate a tcp connection to the billing server on the agreed port. (from now on, I'm going to get lazy, and call the game server "the server", and the billing server "the biller". i'll use g->b and b->g to describe the two directions.) to login: g->b: "SETIDS:serverid:groupid:scoreid" used _only_ for compatibility with older billing servers through the proxy. new billing servers should ignore this command. g->b: "CONNECT:version:swname:zonename:network:password" version is the version of the protocol used. swname is something idenifying the software used, like "asss 1.0.5". zonename is the name of this zone, like "A Small Warzone". network is where this zone is hosted, like "SSCX". password is a password to authenticate this zone. the response will either be this: b->g: "CONNECTOK:billername" billername is something identifying the biller used, like "mybiller 0.29". or b->g: "CONNECTBAD:billername:reason" billername is as above. reason is something describing why the connection was refused, like "bad password". the biller will most likely close the connection after sending a CONNECTBAD, but if it doesn't, the game server should. once you're connected: when a player logs in: game sends: g->b: "PLOGIN:pid:flag:name:pw:ip:macid:contid" pid is the player id assigned to this player by the server. flag is 0 for a normal login, 1 for "i want to create a new player". name is the name that's trying to log in. pw is the password he's using. ip is the address he's connecting from (in dotted decimal). macid is the standard machine id of the player. contid is the id data from continuum players. if the player isn't using cont, it should be empty. if the player is using cont, it will be the cont id, encoded in 128 characters, using plain hex encoding with lowercase letters. biller responds with either: b->g: "POK:pid:rtext:name:squad:billerid:usage:firstused" pid is the player id that was passed in PLOGIN. rtext is additional text that can be delivered to the client. if there are no complications logging in, it should be empty. name is the name assigned by the biller (the biller can change the name of a player if desired). squad is the player's squad. billerid is an id number assigned by the billing server. usage is the number of seconds that this player has ever been connected to this biller. firstused is a string describing when this named account was created, in roughly this form: "1-2-1999 6:13:35" or b->g: "PBAD:pid:rtext" pid is the player id passed in PLOGIN. rtext is some text describing the reason this login was denied. the biller can send this any any time, but will typically send it right after a PLOGINOK message: b->g: "BNR:pid:banner" pid is the pid of the player setting his banner. banner is a 96-byte banner, encoded using standard hex encoding with lowercase letters, so it will be 192 bytes long. when a player sets his banner, the server will update the biller with: g->b: "BNR:pid:banner" pid the the pid of the player setting his banner. banner is the new banner, encoded as above. when a player disconnects from the server, the server sends: g->b: "PLEAVE:pid" when a player sends a ?chat message, the server sends: g->b: "CHAT:pid:channel:sound:text" pid is the sending player. channel is the name of the channel. alternatively, it can be a number signifying which of the player's channels the message is intended for. sound is a sound code, to be interpreted by the client. text is the text of the message. when a player gets a ?chat message, the server receives: b->g: "CHATTXT:channel:sender:sound:text" b->g: "CHAT:pid:number" channel is the name of the channel that this message is on. sender is the name of the player who sent the message. sound is a sound code. text is the text of the message. pid is the pid of a player who received the message. number is what channel that player should see the message as coming from. the CHATTXT message is used so that the biller can send a chat message to many players on one server without sending the full text and sender name to each of them. the contents of the CHATTXT message should be cached on the server, and the text used for any following CHAT messages, until the next CHATTXT. for example, if the server gets "CHATTXT:sscx:player:0:hello" and then "CHAT:22:3", player 22 should see something like "3:player> hello". when a player sends a remote private message: g->b: "RMT:pid:destination:sound:text" pid is the pid of the sending player. destination is the player the message is being sent to. sound is a sound code. text is the text of a message. when a player receives a remove private message: b->g: "RMT:pid:sender:sound:text" pid is the pid of the player receiving the message. sender is the name of the sending player. sound is a sound code. text is the text of the message. when a player sends a squad message: g->b: "RMTSQD:pid:destsquad:sound:text" pid is the pid of the sender. destsquad is the name of the squad whose players should receive the message (no leading #). sound is a sound code. text is the text of the message. when a player receives a squad message: b->g: "RMTSQD:destsquad:sender:sound:text" destsquad is the squad that the message is for. sender is the name of the sending player. sound is a sound code. text is the text of the message. when a player types a command that the server doesn't interpret, or that the server knows should go to the billing server: g->b: "CMD:pid:cmdname:args" pid is the pid of the sending player. cmdname is the name of the command. args is the arguments to the command (what was typed after the command name. when the server wants to send a player some message (usually as the result of a command): b->g: "MSG:pid:sound:text" pid is the pid of the recipient. sound is a sound code. text is the text of the message. when the server wants to send some of its log output to the biller, perhaps so logs document malicious activity can be gatherd and analyzed for many zones at once, it can send: g->b: "LOG:pid:logtext" if the log message refers to the activity of a specific player, the pid field will hold the pid of that player. if not, it should be empty (zero-length). logtext is the text of the log message, in whatever format the server chooses. if the biller wants to send a message to only staff members of a zone, it can send: b->g: "STAFFMSG:sender:sound:text" sender is the optional name of whoever sent this message. if it was generated by the billing server, it should be empty. sound is a sound code. text is the text of the message. if the biller wants to send a message to the entire zone (e.g., for scheduled downtime or other important events), it can send: b->g: "BROADCAST:sender:sound:text" sender is the optional name of whoever sent this message. if it was generated by the billing server, it should be empty. sound is a sound code. text is the text of the message. if the server is going down (for a shutdown or whatever), it should close the tcp socket. if the biller is going down (for any reason), it should close the tcp socket. # dist: public