(Just found that this has been sitting as a Draft for the last six+months...)
Wow, another year goes by without a post. And granted, little time has gone to MMORF, what with life's other concerns and distractions. But, like the tides, my interests ebb and flow, and for now have flown back to MMORF.
I've started a skeleton structure for MMORF, abstracting the various server concepts and even putting together the roughest of text clients for testing purposes. Perhaps it's the complexity of the project, or perhaps it's old-age, but I'm finding myself needing to sketch and list out ideas and concepts a lot more than I used to...
I've been using Fogbugz and Kiln for a few months now, for a variety of projects, and have found that jotting down milestones and future ideas there instead of in in-code comments is working better than I expected. I've also realized that I really need to learn to use a tool like Visio so I can sketch out flows and connections, because my handsketched drawings just don't cut it.
Even though work happens in small bursts and fits, usually within the span of a lunchhour, I'm finding I'm learning the .NET libraries quickly and the cool C# features at the same time. With the Mono system as mature as it is, thanks to the guys at Xamarin, I feel C# and .NET are the right choice for MMORF. The Serialization support means I don't have to worry as much about a protocol between client and server or between servers, because objects can be used as the protocol and can be passed effortlessly between. Indeed, by choosing the method of serialization, I also leave open the ability to watch traffic by leaving it somewhat human-readable in XML, or streaming it in binary form for a bit of speed a little obfuscation.
As with all large projects (at least, for me), doing it so piecemeal has the big disadvantage of ramping up where you left off when you come back to it a day later. Unlike some other projects that I've been trying to work on, though, this one has been churned in my head for a long time (six-and-a-half years!) so the "where was I?" problem is definitely lessened.
Here's hoping that the next post is sooner than a year from now, and has some exciting developments!
Showing posts with label servers. Show all posts
Showing posts with label servers. Show all posts
Tuesday, March 13, 2012
Thursday, July 01, 2010
Protocol
The whole point of this project, as I may have mentioned before, is to develop the servers, the backend, for the roleplaying framework, not the client. Of course, developing one or more clients is to be expected as I work on the project, because much like you'd expect from a blind painter, it helps to have a visual verification that the result is at all accurate; I could work on the server-side code all I want and HOPE it works, but I'd really want to SEE that it works eventually.
Knowing that, I knew that some day I'd be working on a client -- textbased, 2d, 3d, whatever -- but I never thought it'd be so soon. In fact, I'm actually writing a text-based console client before I get any of the "useful" part of MMORF written: even the server-side code that I'm writing to test the client is just login server stuff right now. Where's the good stuff??
Of course, writing the client means that I've had to address the issue of the protocol between the client and the server, which I've briefly discussed before, but have spent a bit of time thinking about already. Two things are important in a protocol, when all things are said and done: it's efficient, and it's debuggable. The second part can always be done regardless of how the protocol is implemented, but its readability corresponds to how easily it is debugged. Sure, you can write loggers and decoders to translate some binary stream to meaningful words for the developer, but when first developing the system, you're better off making it human-readable to start, and worry about the efficiency later, provided you coded the networking subsystems to handle a complete change to the protocol. This means that all communication is handled through functions that generate the protocol packets via a drop-in system, one which can be replaced without anyone being the wiser. In fact, having the client being able to support every drop-in system you've devised based on its ability to detect what's coming down the pipe means no rewriting later in the development cycle.
When I talk about a human-readable protocol, I typically mean an interchange format such as XML, JSON, YAML or even Metaplace's MetaMarkup. It's something that balances readability by humans and parseability by computers. Myself, I tend to lean towards XML, because it handles hierarchical data very well (both structurally and visually), it copes with escaping characters used by the protocol WITHIN the protocol (something which was a recurring theme with MetaMarkup), and because I've had some experience with it as a network protocol.
The only unfun part of developing a protocol is ... developing a protocol. When you get to the binary level and are trying to squeeze as much data through as possible, THEN it might actually be fun, but at the XML level, it can be tedious coming up with the schema for all of the different packets that are going to fly by.
That's why I was quite pleased to find out that the serialization of C# objects results in: XML! Instead of having to come up with an XML protocol schema, all I have to do is come up with an object schema based on all of the communication needed between client-and-server and server-and-server, then pass these objects through the network and let them pop out as objects that need to be handled. Even better, handlers for these objects can actually be part of the object itself.
It's a pretty slick system. It took a bit of designing to come up with a general server framework, allowing the client to handle various login servers (local (object-based) and remote) and client servers (local and remote), but this is done and mostly implemented. I now have a console client that launches its own local login and client servers (internal objects, not even using a loopback network connection) and can send login packets (or rather, serialized login objects). I had to design none of the protocol, instead letting the .NET Serialization system do it for me, and I had to neither write out nor read in the stream of data, deconstituting or reconstituting the meaning. Instead, I create a Login object, call my LoginServerConnection's Send() function with it, and on the other side the LoginServer sees a Login object pop out, which it may deal with as it pleases.
Just think: I'm almost at the point where I can actually design some of the game server and see it working. Amazing.
Knowing that, I knew that some day I'd be working on a client -- textbased, 2d, 3d, whatever -- but I never thought it'd be so soon. In fact, I'm actually writing a text-based console client before I get any of the "useful" part of MMORF written: even the server-side code that I'm writing to test the client is just login server stuff right now. Where's the good stuff??
Of course, writing the client means that I've had to address the issue of the protocol between the client and the server, which I've briefly discussed before, but have spent a bit of time thinking about already. Two things are important in a protocol, when all things are said and done: it's efficient, and it's debuggable. The second part can always be done regardless of how the protocol is implemented, but its readability corresponds to how easily it is debugged. Sure, you can write loggers and decoders to translate some binary stream to meaningful words for the developer, but when first developing the system, you're better off making it human-readable to start, and worry about the efficiency later, provided you coded the networking subsystems to handle a complete change to the protocol. This means that all communication is handled through functions that generate the protocol packets via a drop-in system, one which can be replaced without anyone being the wiser. In fact, having the client being able to support every drop-in system you've devised based on its ability to detect what's coming down the pipe means no rewriting later in the development cycle.
When I talk about a human-readable protocol, I typically mean an interchange format such as XML, JSON, YAML or even Metaplace's MetaMarkup. It's something that balances readability by humans and parseability by computers. Myself, I tend to lean towards XML, because it handles hierarchical data very well (both structurally and visually), it copes with escaping characters used by the protocol WITHIN the protocol (something which was a recurring theme with MetaMarkup), and because I've had some experience with it as a network protocol.
The only unfun part of developing a protocol is ... developing a protocol. When you get to the binary level and are trying to squeeze as much data through as possible, THEN it might actually be fun, but at the XML level, it can be tedious coming up with the schema for all of the different packets that are going to fly by.
That's why I was quite pleased to find out that the serialization of C# objects results in: XML! Instead of having to come up with an XML protocol schema, all I have to do is come up with an object schema based on all of the communication needed between client-and-server and server-and-server, then pass these objects through the network and let them pop out as objects that need to be handled. Even better, handlers for these objects can actually be part of the object itself.
It's a pretty slick system. It took a bit of designing to come up with a general server framework, allowing the client to handle various login servers (local (object-based) and remote) and client servers (local and remote), but this is done and mostly implemented. I now have a console client that launches its own local login and client servers (internal objects, not even using a loopback network connection) and can send login packets (or rather, serialized login objects). I had to design none of the protocol, instead letting the .NET Serialization system do it for me, and I had to neither write out nor read in the stream of data, deconstituting or reconstituting the meaning. Instead, I create a Login object, call my LoginServerConnection's Send() function with it, and on the other side the LoginServer sees a Login object pop out, which it may deal with as it pleases.
Just think: I'm almost at the point where I can actually design some of the game server and see it working. Amazing.
Friday, January 15, 2010
Warming up
As I wait for the new C# 4.0 Nutshell book to arrive, I'm doing more (re)thinking and planning instead of coding. This involves re-reading my old posts, including the one on the servers that would make up the whole system. I wrote that nearly five years ago, so I've still got to decide whether my thinking back then is still reasonable, but I did come up with two other servers that would be useful to have.
chat server
Chatting between players is a core concept to a multiplayer game. But "chat" is a different idea than the talk verb; talking happens at a range from the player's avatar in-world, where chat transcends the virtual world and is instead a meta event. This is for players talking to players, not characters talking to characters.
Dungeons & Dragons Online had a separate chat server -- this was made obvious when the server was down, and the client outright told you so. Ultima Online, after way too long, added chat to the game -- obviously something revealed to be needed, but I've not played UO since it was added, so I'm not sure if it's a separate server or not. Metaplace, too, had added a chat server after a while, helping to connect multitudes of players and developers who would otherwise each be in their own world.
Does this need to be a different server, or should it just be a new verb to a new "room" that spans the "ether" of the whole game world? I think so, because the idea of a separate server allows for non-game-client chat clients to exist; a web-based client or a plugin to poly-IM tools such as Miranda or Trillian could be written to allow players and guild members to chat with friends without having to be running the actual client. Shouldn't they just use some other chat method, separate from the game itself? No, because the whole ICQ-while-playing is an old idea, and is problematic in full-screen games. The communication while in-game needs to be in the client. Also, a game-aware chat system can access game data, allowing lookups of equipment stats, character levels, guild rosters, etc. as part of the chat protocol. This is data that is being exposed more and more by commercial games, allowing players to watch their characters and guilds through webpages or even an API. The idea of an API into the game server's data is a must, of course, for MMORF, and one that I'll have to keep in mind as it's developed, including the chat server's access to it.
patch server
Typically patch servers are used to patch clients, for both the client's logic (rendering, interface, etc.) and the client's assets (art, animations, sounds). This is typically something that happens when the game client starts up; it connects to the patch server, compares its version to the latest, downloads a new executable, or dynamic library, or art file, or data file, or something, and then launches the "real" game client once that's done. This happens in the UO client, the DDO client, and probably every other online game client out there.
Metaplace was a little different; the logic portion of the game client was a Flash program, which was downloaded when you went to the world's site or a site with an embed of it. The patch in this case happened automatically for you. And the game assets were downloaded at each world visit, though your browser could be caching it and not actually downloading. This was required because the same client was being used for myriad worlds, each with assorted sets of assets. This kind of functionality isn't typically needed in a client with a single game target, however, but it COULD be. There's no reason that assets couldn't be streamed as needed, in the background, as the player first logs in. It would allow a game to update itself while running, instead of downtime on the server, and forcing the player to log out to repatch.
The other reason I can see with the pre-patch versus the live patch is that game clients tend to store their assets in large binary files, perhaps for file access reasons, but more likely to help obscure the file format to keep their assets private. On the other hand, assets in Metaplace were just web assets, PNGs and JPGs and MP3s that had to obfuscation. I will certainly be taking the open approach while developing MMORF, allowing for easy and transparent handling of the local version of assets.
I'll soon have to break out the Visio to make some pretty drawings relating all of the different server parts to this project. It all seems clear in my head, but let's see how it looks on paper.
chat server
Chatting between players is a core concept to a multiplayer game. But "chat" is a different idea than the talk verb; talking happens at a range from the player's avatar in-world, where chat transcends the virtual world and is instead a meta event. This is for players talking to players, not characters talking to characters.
Dungeons & Dragons Online had a separate chat server -- this was made obvious when the server was down, and the client outright told you so. Ultima Online, after way too long, added chat to the game -- obviously something revealed to be needed, but I've not played UO since it was added, so I'm not sure if it's a separate server or not. Metaplace, too, had added a chat server after a while, helping to connect multitudes of players and developers who would otherwise each be in their own world.
Does this need to be a different server, or should it just be a new verb to a new "room" that spans the "ether" of the whole game world? I think so, because the idea of a separate server allows for non-game-client chat clients to exist; a web-based client or a plugin to poly-IM tools such as Miranda or Trillian could be written to allow players and guild members to chat with friends without having to be running the actual client. Shouldn't they just use some other chat method, separate from the game itself? No, because the whole ICQ-while-playing is an old idea, and is problematic in full-screen games. The communication while in-game needs to be in the client. Also, a game-aware chat system can access game data, allowing lookups of equipment stats, character levels, guild rosters, etc. as part of the chat protocol. This is data that is being exposed more and more by commercial games, allowing players to watch their characters and guilds through webpages or even an API. The idea of an API into the game server's data is a must, of course, for MMORF, and one that I'll have to keep in mind as it's developed, including the chat server's access to it.
patch server
Typically patch servers are used to patch clients, for both the client's logic (rendering, interface, etc.) and the client's assets (art, animations, sounds). This is typically something that happens when the game client starts up; it connects to the patch server, compares its version to the latest, downloads a new executable, or dynamic library, or art file, or data file, or something, and then launches the "real" game client once that's done. This happens in the UO client, the DDO client, and probably every other online game client out there.
Metaplace was a little different; the logic portion of the game client was a Flash program, which was downloaded when you went to the world's site or a site with an embed of it. The patch in this case happened automatically for you. And the game assets were downloaded at each world visit, though your browser could be caching it and not actually downloading. This was required because the same client was being used for myriad worlds, each with assorted sets of assets. This kind of functionality isn't typically needed in a client with a single game target, however, but it COULD be. There's no reason that assets couldn't be streamed as needed, in the background, as the player first logs in. It would allow a game to update itself while running, instead of downtime on the server, and forcing the player to log out to repatch.
The other reason I can see with the pre-patch versus the live patch is that game clients tend to store their assets in large binary files, perhaps for file access reasons, but more likely to help obscure the file format to keep their assets private. On the other hand, assets in Metaplace were just web assets, PNGs and JPGs and MP3s that had to obfuscation. I will certainly be taking the open approach while developing MMORF, allowing for easy and transparent handling of the local version of assets.
I'll soon have to break out the Visio to make some pretty drawings relating all of the different server parts to this project. It all seems clear in my head, but let's see how it looks on paper.
Monday, March 21, 2005
Servers revisited
Following on the last post, I'll talk about the "work" involved in each portion. We'll do them backwards, as the design of some can influence others.
World servers
Basically a database. We need to be able to add (INSERT), remove (DELETE), find (SELECT) and change (UPDATE) the object records. These objects would have many properties, and would most likely have to support a wide variety of properties, so a schema would have to be flexible (or not required). As to whether or not this is simply implemented as an SQL database, or as some sort of SOAP server, still needs to be visited, but the world server should be written in such a way that it has no knowledge of the world itself, and thus the same setup could be used from one world to the next (though the data within might not transfer between). There should be no "getSword()" or "getAlienStats()" specific to the protocol for the world server. Simple "getObject()" "createObject()" etc.
Compute servers
These, for the most part, are script engines. They run multiple scripts (written in a language I haven't begun to figure out), all of which interact with the objects in the world. These might range from creating new objects (a flower sprouts), refreshing objects (the mine produces 20 more ore now), spawning encounters (orc ambush, bandit raid, elephant stampede). They might be watching when PCs approach, might be set to timers, or set to randomly act. They might listen to PCs, in the case of NPCs. They might react to an NPC being attacked.
The scripts, and thus the compute servers, will communicate with: compute servers, either itself or others, to let other objects know that something is happening to them (NPC X is attacking NPC Y, the volcano just exploded and poured lava onto that flower, etc.); world server, to get/set/add/remove objects; and the client servers, to inform them of changes within their clients' view (monsters just appeared, you now see a field of carrots, it's raining).
The compute servers, therefore, should also have no "knowledge" of the world; they should just run scripts, all of the same language. This scripting language does the same thing in a fantasy world as it would in a futuristic world, as it would in a historical world: at time X a monster Y will appear in region Z; if NPC A sees a creature of type B, it will run away. The values of X, Y, etc. are specific to the world, but that is up to the script, not the compute server. In the end, the compute server acts on behalf of the many scripts it's running, and thus speaks the generic protocol of "getObject()" etc. to the world server, and "showObject()" etc. to the client server. Therefore, a compute server should be usable from one world to the next, much as the world server is, though it will likely be loaded with different scripts.
Client servers
Here we get a bit different. The client server is largely responsible for enforcing the rules of the world. It has to decide whether or not the commands from the client are valid (never trust the client!) as well as if the commands are successful. Can the character pick that item up? Can they use that object? It also has to relay in-game events back to the client, though this is largely a communicative role, as we trust the results of what the compute server does.
Does this require the client server to be world-specific? Or is it possible to abstract all the rules into a set of numbers, or perhaps formulate them into a few dynamic libraries that are plugged in? Or even write them in the same scripting language in which the rest of the world is run? Should these rules be moved, then, into the compute server instead, and just leave the client server's role as a trusted version of the client itself?
The more I think about it, this is the way it should be. If a player tries to use an object, that object's script should run on the compute server, and it will decide whether that's allowed, whether the character is close enough, etc. This way, world-specific rules are handled by the scripts.
So is there a need for a client server? Yes, because we still need a sanity checker; something that can determine if the requests coming from the client are "well formed". Are they sending commands too fast? Did they somehow say "eat the chair" even though the client is designed to not allow that action (and thus the user must have forged a packet, or hacked the client)? Did they try to wear a monster on their head?
While a lot of these things could also be handled in the scripts, there will be other things that aren't going to be definable in the scripting language. Maybe. Until world design actually starts (and client design, too), this is an open question, as is how generic the client server can be written for a specific world.
Login server
This can probably be done very generically, as all worlds most likely need a way to login, might need a way to choose the world they want to connect to, need a way to choose from a possible list of characters to play (or, to accept character creation from the client). With the exception of character creation, this is all very generic to any world.
Character creation can either happen through the login server (as a series of communications between the client and, perhaps, the client server), or could be done fully on the client (though verified by the client server). This leaves out any world-specific names, classes, or numbers from the login server. It's just a vessel for authenticated connectivity between a client and their world.
Client
Though not a server, we might as well discuss it here. While it might seem that a client will be very world-specific, I don't think it has to be so. As long as the client engine (text, 2d, 2.5d, 3d) supports external resource files, the same client can run the fantasy world as it can the futuristic one. Looking at the files for Ultima Online, for instance, you could change the majority of it into a completely different world just by editing them (with a lot of time to redraw every item, monster and tile in a different setting). The only thing remaining would be the text labels and messages that are received from the server.
The client is all about the interface; how to see what's going on, and how to influence the goings-on. It's all about "walk here", "pick this up", "attack that", "say this to her". Nothing world-specific. The same client, if done right, will just access a different set of data files to get its graphics, it's themed interface (skill lists, gump graphics, etc.) but all games boil down to the same actions (though how the client performs these actions is what can make or break the game.
All the above basically shows my motivation for this project: that I should be able to write a foundation on which a variety of games can be "plugged" into. Players would then download different resources (graphics, sound), and the designers would design new worlds (in the form of the scripts that run on the compute servers). And these, really, are a separate project, though I might just talk about them here anyway...
World servers
Basically a database. We need to be able to add (INSERT), remove (DELETE), find (SELECT) and change (UPDATE) the object records. These objects would have many properties, and would most likely have to support a wide variety of properties, so a schema would have to be flexible (or not required). As to whether or not this is simply implemented as an SQL database, or as some sort of SOAP server, still needs to be visited, but the world server should be written in such a way that it has no knowledge of the world itself, and thus the same setup could be used from one world to the next (though the data within might not transfer between). There should be no "getSword()" or "getAlienStats()" specific to the protocol for the world server. Simple "getObject()" "createObject()" etc.
Compute servers
These, for the most part, are script engines. They run multiple scripts (written in a language I haven't begun to figure out), all of which interact with the objects in the world. These might range from creating new objects (a flower sprouts), refreshing objects (the mine produces 20 more ore now), spawning encounters (orc ambush, bandit raid, elephant stampede). They might be watching when PCs approach, might be set to timers, or set to randomly act. They might listen to PCs, in the case of NPCs. They might react to an NPC being attacked.
The scripts, and thus the compute servers, will communicate with: compute servers, either itself or others, to let other objects know that something is happening to them (NPC X is attacking NPC Y, the volcano just exploded and poured lava onto that flower, etc.); world server, to get/set/add/remove objects; and the client servers, to inform them of changes within their clients' view (monsters just appeared, you now see a field of carrots, it's raining).
The compute servers, therefore, should also have no "knowledge" of the world; they should just run scripts, all of the same language. This scripting language does the same thing in a fantasy world as it would in a futuristic world, as it would in a historical world: at time X a monster Y will appear in region Z; if NPC A sees a creature of type B, it will run away. The values of X, Y, etc. are specific to the world, but that is up to the script, not the compute server. In the end, the compute server acts on behalf of the many scripts it's running, and thus speaks the generic protocol of "getObject()" etc. to the world server, and "showObject()" etc. to the client server. Therefore, a compute server should be usable from one world to the next, much as the world server is, though it will likely be loaded with different scripts.
Client servers
Here we get a bit different. The client server is largely responsible for enforcing the rules of the world. It has to decide whether or not the commands from the client are valid (never trust the client!) as well as if the commands are successful. Can the character pick that item up? Can they use that object? It also has to relay in-game events back to the client, though this is largely a communicative role, as we trust the results of what the compute server does.
Does this require the client server to be world-specific? Or is it possible to abstract all the rules into a set of numbers, or perhaps formulate them into a few dynamic libraries that are plugged in? Or even write them in the same scripting language in which the rest of the world is run? Should these rules be moved, then, into the compute server instead, and just leave the client server's role as a trusted version of the client itself?
The more I think about it, this is the way it should be. If a player tries to use an object, that object's script should run on the compute server, and it will decide whether that's allowed, whether the character is close enough, etc. This way, world-specific rules are handled by the scripts.
So is there a need for a client server? Yes, because we still need a sanity checker; something that can determine if the requests coming from the client are "well formed". Are they sending commands too fast? Did they somehow say "eat the chair" even though the client is designed to not allow that action (and thus the user must have forged a packet, or hacked the client)? Did they try to wear a monster on their head?
While a lot of these things could also be handled in the scripts, there will be other things that aren't going to be definable in the scripting language. Maybe. Until world design actually starts (and client design, too), this is an open question, as is how generic the client server can be written for a specific world.
Login server
This can probably be done very generically, as all worlds most likely need a way to login, might need a way to choose the world they want to connect to, need a way to choose from a possible list of characters to play (or, to accept character creation from the client). With the exception of character creation, this is all very generic to any world.
Character creation can either happen through the login server (as a series of communications between the client and, perhaps, the client server), or could be done fully on the client (though verified by the client server). This leaves out any world-specific names, classes, or numbers from the login server. It's just a vessel for authenticated connectivity between a client and their world.
Client
Though not a server, we might as well discuss it here. While it might seem that a client will be very world-specific, I don't think it has to be so. As long as the client engine (text, 2d, 2.5d, 3d) supports external resource files, the same client can run the fantasy world as it can the futuristic one. Looking at the files for Ultima Online, for instance, you could change the majority of it into a completely different world just by editing them (with a lot of time to redraw every item, monster and tile in a different setting). The only thing remaining would be the text labels and messages that are received from the server.
The client is all about the interface; how to see what's going on, and how to influence the goings-on. It's all about "walk here", "pick this up", "attack that", "say this to her". Nothing world-specific. The same client, if done right, will just access a different set of data files to get its graphics, it's themed interface (skill lists, gump graphics, etc.) but all games boil down to the same actions (though how the client performs these actions is what can make or break the game.
All the above basically shows my motivation for this project: that I should be able to write a foundation on which a variety of games can be "plugged" into. Players would then download different resources (graphics, sound), and the designers would design new worlds (in the form of the scripts that run on the compute servers). And these, really, are a separate project, though I might just talk about them here anyway...
Servers
I've been giving thought to what kind of servers I want to see in this engine, lately. The reason for so many servers is to allow the world to be (infinitely) expandable, limited only by the available hardware (and not the speed of that hardware).
Some games (Ultima Online), split their world into different parts, having a server run each part of the world. These splits are static (same for every Ultima shard) and noticeable by the players: the client "skips" a little when you cross a server boundary; NPCs (until recently, it seems) couldn't cross them; and information across the boundary was incomplete (PCs/NPCs would "echo" their location on the other side). Everquest, from what I hear, has things even more blatant - you actually cross into a new zone, where the screen blanks/blinks/loads and you're in a new area, and nothing but players can cross this boundary (and it's not seamless).
I want to avoid these problems. They break immersion; when you play a massively-multiplayer game, or are in a virtual world, you want it to be a world, not a bunch of disjointed rooms or areas. Additionally, while the technical reason for having multiple servers is most likely to distribute load for many players, these methods fail if all the players get together in one area (for an in-game event, for example). Optimally, then, I'd like to have a system where, given enough resources (read: money), one could just keep adding machines to a world, and allow it to use the available hardware to share out the work. No fixed boundaries - they could be moved around, either at server-setup time, or maybe dynamically?
This is what I've come up with for now. It might change, as I might decide more servers are needed, or that, perhaps, some are not. If I had some sort of chart-drawing program, I'd post a picture, but for now, I hope I can describe the doodle I have in front of me well enough to make it understood.
Login servers
These servers are the only servers exposed to the outside world. They are connected to by the client, and are the gateway for all commands from the client to the virtual world. These servers do authentication, character creation, and perhaps account management. They provide the list of worlds (if there are more than one), and communicate further in the "chain" to the client server.
You can have a single login server (if your virtual world is small), or you can have multiple ones; in the case of more than one, there would probably be a proxy at the "front" of them all to distribute the client connections evenly amongst all the login servers. A client would connect to the one login server and stay connected to it for the life of their session. Also, the client server that the login server connects to would remain the same for the life of the client's session.
The number of login servers would be a function of how many (expected) users the worlds have (connected at any one time). More can be easily added, as only the proxy would need to know to add it to its list of possible choices. The login server needs to have fast throughput, as it's funneling commands to and from the client, but wouldn't need much in the way of actual processing power, or storage.
Client servers
Client servers can be thought of as clients, in that they do everything on behalf of the player, if only we could trust them not to cheat. At this point, we believe they are who they say they are (authenticated). In the client server, we would verify commands from the player (too many commands sent at once, etc.), and decide whether or not these commands were valid (permission to pick that up, close enough to pick it up, etc.) A client server can talk to more than one compute server at once, depending on how they're implemented, and possibly the world server.
You can have a single client server (if your virtual world is small), or you can have multiple ones; as with the login server, you would probably have a proxy for the client servers so the connections between the login servers and the client servers are shared evenly to distribute load. Multiple login servers can connect to a single client server, so they client server acts as multiple players. The client server could be on the same machine as the login server; that is, they could be two separate processes running on the same hardware, communicating through IPC (or TCP/IP loopback). They could, too, be the same process, though this prevents scaling.
The number of client servers would be a function of how many (expected) users the world has (connected at any one time). Where the login servers had to account for every player on every world, client servers just need to account for players on a single world. More client servers could be added, and the proxy would just need to be configured to know about them. The client server would need to have fast throughput, as it's funneling commands much as the login server is, as well as decent processing power, as it might have to do some sanity checks on the data received from the client (by way of the login server).
Compute servers
These are the core processors of the virtual world. They move NPCs, they trigger events, and they handle player actions. Really, they run scripts for the most part, and communicate with the world server.
You can have a single compute server (if your virtual world is small, or you can have multiple ones. They might be partitioned so one (or more) run the NPCs, another (group) for triggered events (spawn of monsters and resources), another (group) for handling client interaction, etc. Or, one (or more) might handle area A of the world, another (group) area B, and so on. Compute servers might also communicate with each other, to let one know that an object has moved between areas. In this way, the compute server acts as a client server, "requesting" that this object be allowed to step here or be placed there. The compute server, too, could be on the same machine as the client server (and the login server), if the world is small enough, each running as a different process. This could speed communication between them, again using IPC, local TCP/IP, etc.
The number of compute servers would depend on the complexity of the world; how large, how many events happen at any given time, how many triggers are waiting to be run, how many NPCs are meandering, etc. Adding another compute server would probably require bringing the world down to reconfigure which one handles which tasks, whereas login servers and client servers could probably be added live (where their proxies were just "refreshed" with the new server's information). While it's possible to design the compute servers so they, too, could be added dynamically, "live", that would require a lot of extra work. Indeed, allowing the compute servers to change their workload on-the-fly would be optimal, but a much bigger coding task.
World servers
This is basically the world database. It knows about every object, and every property about them. It backs up the data, it provides the data to the client servers, it changes the data on behalf of the client servers. It, most importantly, locks the data when two client servers are trying to affect the same object at the same time. It is nothing but a specialized database. Maybe even not that special... could be just mySQL, Oracle, or something similar.
You would likely have just one world server. While it could be implemented on any number of machines, perhaps for redundancy, perhaps to share the load (player information there, NPC information there, item information here), but the point-of-view to the compute servers would be of just one central database of information about the world. Whatever the internals of the world server, it would be its responsibility to keep the data sane: to never "lose" an object, to never allow duplication of an object (duping), etc. The world server, could, as before, be on the same hardware as the compute server (and the client server, and the login server...) if the world is small enough. Communication could then be improved in a world that's small enough to allow one physical machine to handle all these processes, but of course a world that small may not need such performance. It's the large-scale worlds which require multiple machines that also require efficient communication between them.
To be continued...
Some games (Ultima Online), split their world into different parts, having a server run each part of the world. These splits are static (same for every Ultima shard) and noticeable by the players: the client "skips" a little when you cross a server boundary; NPCs (until recently, it seems) couldn't cross them; and information across the boundary was incomplete (PCs/NPCs would "echo" their location on the other side). Everquest, from what I hear, has things even more blatant - you actually cross into a new zone, where the screen blanks/blinks/loads and you're in a new area, and nothing but players can cross this boundary (and it's not seamless).
I want to avoid these problems. They break immersion; when you play a massively-multiplayer game, or are in a virtual world, you want it to be a world, not a bunch of disjointed rooms or areas. Additionally, while the technical reason for having multiple servers is most likely to distribute load for many players, these methods fail if all the players get together in one area (for an in-game event, for example). Optimally, then, I'd like to have a system where, given enough resources (read: money), one could just keep adding machines to a world, and allow it to use the available hardware to share out the work. No fixed boundaries - they could be moved around, either at server-setup time, or maybe dynamically?
This is what I've come up with for now. It might change, as I might decide more servers are needed, or that, perhaps, some are not. If I had some sort of chart-drawing program, I'd post a picture, but for now, I hope I can describe the doodle I have in front of me well enough to make it understood.
Login servers
These servers are the only servers exposed to the outside world. They are connected to by the client, and are the gateway for all commands from the client to the virtual world. These servers do authentication, character creation, and perhaps account management. They provide the list of worlds (if there are more than one), and communicate further in the "chain" to the client server.
You can have a single login server (if your virtual world is small), or you can have multiple ones; in the case of more than one, there would probably be a proxy at the "front" of them all to distribute the client connections evenly amongst all the login servers. A client would connect to the one login server and stay connected to it for the life of their session. Also, the client server that the login server connects to would remain the same for the life of the client's session.
The number of login servers would be a function of how many (expected) users the worlds have (connected at any one time). More can be easily added, as only the proxy would need to know to add it to its list of possible choices. The login server needs to have fast throughput, as it's funneling commands to and from the client, but wouldn't need much in the way of actual processing power, or storage.
Client servers
Client servers can be thought of as clients, in that they do everything on behalf of the player, if only we could trust them not to cheat. At this point, we believe they are who they say they are (authenticated). In the client server, we would verify commands from the player (too many commands sent at once, etc.), and decide whether or not these commands were valid (permission to pick that up, close enough to pick it up, etc.) A client server can talk to more than one compute server at once, depending on how they're implemented, and possibly the world server.
You can have a single client server (if your virtual world is small), or you can have multiple ones; as with the login server, you would probably have a proxy for the client servers so the connections between the login servers and the client servers are shared evenly to distribute load. Multiple login servers can connect to a single client server, so they client server acts as multiple players. The client server could be on the same machine as the login server; that is, they could be two separate processes running on the same hardware, communicating through IPC (or TCP/IP loopback). They could, too, be the same process, though this prevents scaling.
The number of client servers would be a function of how many (expected) users the world has (connected at any one time). Where the login servers had to account for every player on every world, client servers just need to account for players on a single world. More client servers could be added, and the proxy would just need to be configured to know about them. The client server would need to have fast throughput, as it's funneling commands much as the login server is, as well as decent processing power, as it might have to do some sanity checks on the data received from the client (by way of the login server).
Compute servers
These are the core processors of the virtual world. They move NPCs, they trigger events, and they handle player actions. Really, they run scripts for the most part, and communicate with the world server.
You can have a single compute server (if your virtual world is small, or you can have multiple ones. They might be partitioned so one (or more) run the NPCs, another (group) for triggered events (spawn of monsters and resources), another (group) for handling client interaction, etc. Or, one (or more) might handle area A of the world, another (group) area B, and so on. Compute servers might also communicate with each other, to let one know that an object has moved between areas. In this way, the compute server acts as a client server, "requesting" that this object be allowed to step here or be placed there. The compute server, too, could be on the same machine as the client server (and the login server), if the world is small enough, each running as a different process. This could speed communication between them, again using IPC, local TCP/IP, etc.
The number of compute servers would depend on the complexity of the world; how large, how many events happen at any given time, how many triggers are waiting to be run, how many NPCs are meandering, etc. Adding another compute server would probably require bringing the world down to reconfigure which one handles which tasks, whereas login servers and client servers could probably be added live (where their proxies were just "refreshed" with the new server's information). While it's possible to design the compute servers so they, too, could be added dynamically, "live", that would require a lot of extra work. Indeed, allowing the compute servers to change their workload on-the-fly would be optimal, but a much bigger coding task.
World servers
This is basically the world database. It knows about every object, and every property about them. It backs up the data, it provides the data to the client servers, it changes the data on behalf of the client servers. It, most importantly, locks the data when two client servers are trying to affect the same object at the same time. It is nothing but a specialized database. Maybe even not that special... could be just mySQL, Oracle, or something similar.
You would likely have just one world server. While it could be implemented on any number of machines, perhaps for redundancy, perhaps to share the load (player information there, NPC information there, item information here), but the point-of-view to the compute servers would be of just one central database of information about the world. Whatever the internals of the world server, it would be its responsibility to keep the data sane: to never "lose" an object, to never allow duplication of an object (duping), etc. The world server, could, as before, be on the same hardware as the compute server (and the client server, and the login server...) if the world is small enough. Communication could then be improved in a world that's small enough to allow one physical machine to handle all these processes, but of course a world that small may not need such performance. It's the large-scale worlds which require multiple machines that also require efficient communication between them.
To be continued...
Subscribe to:
Posts (Atom)