Here's a rough draft of the network protocol specification. I'm calling it RFC 1 (RFC stands for Request for Comments).
NullpoMino Protocol 1.0 Specification
This is the promised table of opcodes that I've come up with so far. I left some room in the game opcodes area for expansion, and I feel like it would probably be best if we could finalize the design of network games and their communication before this is set in stone.
NMP opcode table
When this proposal is acceptable, I'll begin work on a reference implementation server which uses the protocol.
There may not be a need for a three-stage connection handshake. It seems perfectly sufficient to me to skip the server sending WELCOME and have the client send its version and any connect-options it wants which the server will then confirm or refuse.
ReplyDeleteIn general, I like bit packing for efficiency reasons, but binary protocols can be troublesome and hard to extend if done wrong. A generic encapsulation format for messages and message fields - that is, something that can be parsed whether or not you actually support the commands in question - seems most desirable. You might look at BitTorrent for an example of a similar thing. The intent is, rather than be like, "here function, have this chunk of binary data", you have already processed and validated the code and you pass it to the relevant function with proper parameterization, etc.
A standard field for a timestamp (which could optionally go unused for some messages, but I don't see why it would need to) would be good, I think, since synchronization and latency are concerns. If every participant timestamps every message, we get useful information without requesting it explicitly.
In fact, I'd like to see standard fields ala IRC for: timestamp, source, command, destination, [optional parameters], since these fields will be relevant in most cases. This will help with compatibility and organization.
Some opcodes should have more information. For example, I assume KICKED is supposed to mean "YOU got kicked", but what gets sent when someone else gets kicked?
Organizationally speaking, it can be useful to group kinds of responses like many protocols do, for example 400-series in HTTP for errors. With a hard limit of 256 commands, this is a bit trickier to organize, but you may see some utility in bit masking if you set bits for certain explicit meanings, for example: high bit = success or error, next bit or two might describe the target scope (channel, global, private), etc.
I recently learned something useful about password hashes: USE BCRYPT :)
In general, opcodes can be as verbose as necessary, since the way you're going about it will have them as constants in the source code rather than text transmitted on the wire. With that in mind:
k-line and g-line actually have specific meanings that don't apply here; I'm fond of IRC, but even IRC users tend not to know the exact specifics of these commands ;)
ACC can be misread as access instead of account
GMACCGRB is one of the more convoluted entries
There is a GETOPTS but no SETOPTS, assuming getopts is a list of voluntary options
There are no provisions for managing who has access to do what to a room
ECHO and PING are generally redundant
GMTARGET inherently may not support multiple targets [forward-looking comment]
One-byte opcodes 'for the first version' will make cross-version compatibility if there are ever more opcodes difficult
In general, I think the list covers most things (and what it doesn't, will get covered when you run into it and are like, "oh, I need that"). As I was learning with databases, naming conventions can be extremely useful.
I think you could benefit from taking advantage of naming conventions here, too. For example:
ERROR_NO_ACCESS
ERROR_ROOM_FULL
ERROR_BAD_COMMAND
REPLY_OK
REPLY_USER_LIST
EVENT_JOIN
EVENT_PART
EVENT_LOSE
EVENT_MESSAGE
... and so on. This makes it both easier to understand what's going on and easier to find/use, as well as making some fundamentals clear for later additions.
I took a preliminary couple passes down the list to see if I noticed anything left out, but it's 2am and I'm not confident I've given it due consideration yet, so stay tuned for more :)
One more point in favor of ts/source/cmd/target: the server can appropriately relay messages to their needed targets even if it doesn't know what they mean. This enables the server to be "out of the middle" for more items, which I think would be useful. A distinction may need to be made between commands that get passed directly to users (or rooms, etc.) as-is or ones that are intended for the server to parse. The mentioned bit masking technique might make this convenient.
ReplyDelete