One thing that is very important to MMP is inter-server connections. I know you try to simulate this by using clients as backend servers, but this is not true peer-to-peer. For example, if you want a login server that handles logins for all shards (a single persistant world). This login server would have to be connected to the shard server and both servers must be connected to clients. See the image of my planned network topology:
There are n shard servers connected to the database server and m service-servers (shown as 'zone server' and 'ai server', but can be anything) per shard server.
Another network topology for MMP is using serveral front-end servers (zone servers) per shard. This is the idea of the marketed '3DGS MMO' (using session_connect), but if those servers cannot comunicate with eachother, you will get in trouble. If a player is transfered from zoneA to zoneB, the data about that player cannot be passed through the client (insecure) and cannot be passed through the database-server if it is also 3DGS based (would require p2p), so you either have to run them on the same server and use files (scalable!!) or use a 3rd party solution for connecting to the database from multiple servers simultaneously. If you go 3rd party anyway, why not go the intuitive route and communicate directly between the servers.. This limitation will also make it impossible to have seamless zones, since the zoneA server can never 'see' entities located at the boundaries of zoneB.
Another problem with 3DGS MP that you cannot get around is the fact that the whole design is flawed from a security point of view. The client can arbitrarily update the servers variables! The only thing it requires to change global or playercharacter properties is sending on the right index. Instead of asking the server 'hey I've just read this input [implicit:]so you'll have to change playercharacter property X to value Y' it says 'property X of my playercharacter now has value Y'. You'll say: but we can check the legitimacy of incomming data with the network events. Wrong, the client decides on what index to send and it's impossible to check all variables periodically for illegal changes.
There is no easy way to correlate a message with its sender. Let alone a secure way. If I remember correctly, there is no way to see where a string or var came from in the network events. So the player handle or ID must be encoded in the array or string. And who encodes it? Right, the client is once again telling the server what to do.
Well you're right, that might not be 10% of all networking problems, but here are some more things that, although you can work around them, are still problematic:
-No efficient way to send multiple types of data in one message. The most flexible workaround here is to use strings and encode nummerical data aswell as lexical data in it, and use a seperator character. "237;mypassword;myuserID" for player 237 wanting to login. You don't want to see the str_*** junk that is needed to seperate a complex message into seperate variables.
-Native entity updates. Yes this is a flaw aswell. It is intended to make things easyer but I'm convinced there is no "one size fits all" algorithm for movement prediction (and IMHO movement prediction is the wrong approach anyway; see article). Thus every MP application, no matter how trivial, will turn it off (if you want to provide a lag-free game experience).
-Sending data to specific clients. You and I have got this working, but it's not that simple and once again requires tons of hacks.
-No propper way of timestamping packets.
-Network statistics (F11) are unreliable in my experience.
-No way to connect to non-3dgs applications. I agree this is not a problem for most, but it is for me.
Here is how I hope to solve these issues with my plugin. Let me know if you spot any design flaws, artificial limitations, etc.
It is possible to set the maximum number of incomming and outgoing connections, the local listening port and the networking thread priority. You can start and stop the networking engine at any moment. You can connect to any number of IP:port combinations. You can send prioritized and reliable or unreliable packets. You can also specify an ordering channel, so that packets in the same channel can be ordered chronologically.
The really great thing are the per-message type event functions. Each packet has a first byte which is used to describe the kind of packet. This char is what I call the MessageID. You can assign an event function to each MessageID, including the internal packets. So for example, if you set an event function on the MessageID:ID_NEW_INCOMING_CONNECTION (#defined as 16), your function will be called when a new client has joined. Each event function will be passed a localy unique SystemID (from who the packet originated) and the packet data. This SystemID is also used in all other functions, including send().
Creating packets can be done by simply initializing a struct and sending it away, or more sophisticatedly, by using the serialization and deserialization functions. These alow you to 'line up' arbitrary data in your packet. For example, consider this packet:
[char messageID][var someVar][string optionalString]
The serialization functions allow you to write it like this:
->write the messageID. Say we choose 123 for this kind of message.
->write the var to packet X
->write a bool (a single bit) to the packet, indicating if the next parameter is included
->write the string if you had set the bool to true or don't write the string if it is false.
This allows dynamic deserialization, allowing you to save loads of bandwith in some situations, as well as sending an arbitrarily sized list of parameters (like a list of players to send a chat message to).
The serialization functions also allow you to write compressed strings, vectors and arbitrary data.
Haven't looked at it too closely, but I think it will be easy to add voice communications and an autopatcher, which are both included in RakNet.
Pfew, that was a long post. I'm tired and don't feel like reading it all again, so excuse me if it is full of nonsense