Just like World of Warcraft hosts every single area on a separate computer, you too can mimic behavior like that. Instead of 100 players per DD, you'll get next to none on most DDs and maybe a few more in congested areas like towns. Furthermore, you can shut down areas not in use as well (similarly to how you can unload map areas not in use).
The main requirement for this to work is MySQL and some extra open ports, along with any extra computers you'd be using to do the hosting. Last weeks DevTalk by Stephen001 covered a little information on MySQL, and if you don't know how it works I suggest looking into it before this tutorial. The reason using MySQL here is optimal (if not required) is that you're going to have multiple worlds all requesting information on players and other worlds simultaneously - This fits a database much better than savefiles.
The basic idea behind how multi-server games work, is that you fashion your game so that it can be hosted with parameters that tell it to load a specific map. When a player approaches the entrance to a new map, they're then link()'ed to it. The new map receives the player, loads the characters player, equipment and so on. There are a whole number of steps in between the two points I just mentioned, particularly so if the map the player is trying to get to is not already being hosted. Below is a simple diagram that sketches out the general theory of DD-to-DD transportation:
Step 1: Address resolution
However it happens (through a teleport verb, by stepping onto a turf, using an item, etc..), we have a need to move a player from one DD to another. The first step is to figure out whether the map is already being hosted and if so: where.Since we store all data on the running world(s) in the MySQL DB, this just takes a simple query to the database. For part 1, we assume that the map we're trying to get to is actually up already. Now we have an IP and a port to the world we want to get to, returned by an SQL statement similar to this:
"SELECT * FROM our_database.worlds_table WHERE name=īRed Forestī"If the statement doesn't return any results, its not up. But for now, assume its up and is located on the internet address 85.85.85.85:1234.
Step 2:Handshake
You may have a need to block players from going somewhere specific; or maybe you're creating a game where you have private instances that only allow certain players to enter. Like a group instance in World of Warcraft - Wouldn't be very group-instance-like if any random person could just pop into yours, now would it?The handshake process is there to allow the world you're trying to move the player to a chance to go, 'No!'. This happens via a world.Export() to the world in question, where we ask it whether the player in question can enter the world. It might look like this:
world.Export("byond://85.85.85.85:1234?action=handshake&player=player_id")The response to the Export() would either be a yes or a no. If its a no, we drop it there and discontinue. If yes, we continue to step 3.
Step 3: The link()
Now we've got an address to the destination world, and we've been allowed to move the player there. link() allows us to send a client to a different BYOND world, by using a byond:// link that is formatted as follows: byond://ip:port?topicFor security reasons, we have our world require a topic that looks a certain way and is encrypted. It would be more secure to mimic sessions by having the handshake return a unique connection ID, but web security is beyond the scope of these articles as well. For almost all intents and purposes, this process is safe because people have no idea how the links are formatted and what the encryption method and key phrase is.
In my case, link()s are currently formatted like so:
byond://ip:port?action=link_player&player=player_id&x=x_coor d&y=y_coord&z=z_coordI put x, y and z-coordinates in there so I could quickly tell the destination world where I wanted the player to be in the new world. There are other conceivable ways of avoiding having to do that, but it fits fine for our intent here. The link is then encrypted with my private key, and decrypted on the other end. Note: Export()'s are encrypted the same way.
Once you link() a player somewhere, the topic will be available under client/New(Topic) in the destination world. So if a player has no topic or the topic is garbled when you decrypt it, the player either tried connecting directly to a world by themselves or you made a mistake somewhere. Whether you want players to be able to connect to worlds directly themselves or not depends on the game. For me the answer is no: Players connect to a 'Login Server' like they do in MMORPGs, which then moves them to the appropriate map. So players with no Topic or a bad topic are instantly deleted again or sent back to the Login Server. For the duration of these tutorials we assume that my setup is the way you want it done. In the next part, we'll look at what happens if the map isn't already up and how that looks.
At the conclusion of these articles you should have a solid idea of how all the components to a system such as this work, and I should have hopefully brushed up the system in time for public release - So that you can take that newfound knowledge along with a library or two of mine, and set your game up to work with this with relative ease!
---
Alathon is the sole programmer and designer of the BYOND game 'Schism'; Schism is about the power struggle between kingdoms fighting over control of the 4 worlds in their Universe, where players can claim territory, build cities, participate in large battles and watch the world evolve on its own as NPCs fight to survive and expand.
Alathon is a 20 year old Dane who first encountered BYOND back in 2001. Having taught himself bits and pieces of C/C++ working on MUDs, he quickly took a liking to BYOND and has stuck around on and off ever since. Currently, Alathon writes the Weekly Digest as Community Manager and moderates the Developer forums.
This is definitely something to consider for those developers which are working on large-scale RPG's.