|
To recap , Ulysses Agenda uses a peer-to-peer networking structure with a central core server in the middle of the mesh that is responsible for centralized, persistent state management for the peer mesh. This allows players to have their characters stored on the server and not worry about it. They can also play from any .NET 3.0-enabled machine and still use the same character.
Basically, the concept here is that every game client is a peer on the same mesh. This lends itself extremely well to the notion of the ESB or Enterprise Service Bus. The concept behind ESBs is that you decouple information being passed in messages from the underlying message transport layer, giving programmers a "fire and forget" method of "dropping" messages onto the backbone and simply knowing that whatever service needed that message will pick it up. Its a really powerful pattern and, if implemented well, can realize some incredible gains in flexibility, time-to-market, scalability, and performance.
If you've been reading any of my blog posts (and I know all three of my readers have been!) then you know that I'm not just about the gaming. My goal in life is to teach people. I want to show people how to code, and I want to show them how to code well and make the right decisions and use the right architectures. Rather than using a stuffy business model sample, I like to use examples that can be more easily related to larger demographic groups - games.
Ulysses Agenda is going to (hopefully) be that dream realized. It will, when finished, provide best practices and solid code examples for WPF, WCF, and WF and much more. The topic of this post relates to the networking design. Basically it works like this:
Each discrete area of interest is a peer channel. There might be a peer channel called net.tcp://ulyssesagenda/nav/andromeda. Inside that mesh, all the traffic that is localized to the andromeda galaxy might take place. You would expect to see NPC and player movements both broadcast into this channel. Here's where it becomes more like an ESB than anything else: Ulysses Agenda doesn't care who posts the messages on the channel. By that I mean this: by default, UA's Universe Server is the sole controller of NPCs (through Workflow Foundation). As NPCs change location within the memory space of the Universe Server, they broadcast their new locations on the navigation channels. The other peer clients (UA Game Client) will be running radar sweeps and will receive radar pings, instantly updating their radar screens as NPCs and other players move. Again - the client doesn't care if its an NPC or a player moving. The central Universe Server broadcasts NPC movements and individual players broadcast their own movements.
So now you're an enterprising programmer. You want to add an entirely new race of NPCs into the game that are controlled by a single player. In other words, you've got one player sitting at a console controlling the movements and actions of an entire race of NPCs, playing UA like a mini strategy game. How is this possible without recoding the game? Easy. Your own client can listen in on all the meshes and put new information into the mesh, including the movements of your own NPCs. In essence, Ulysses Agenda is loosely coupled and infinitely expandable simply because of the mechanism of communication between peers.
Each channel of communication in UA is like a mini-ESB. The game client drops a message on it (like "Bob Attacks Joe for 20 damage"). Other game clients on that channel respond to it by modifying local state, playing a noise indicating taking a hit, and so on. Now, what if you want to be able to go to a website and look at a record of the "Top 10 Battles of the Day" that took place within a given universe. You could modify the universe server and recompile it, sure. However, you could also create an entirely new application that simply listens on all of the combat channels and logs the messages, creating a persistent scoreboard that can then be read from an ASP.NET website.
In short, using this architecture I can produce small pre-packaged units of functionality and add them to the core game, making them part of the core game itself. This gives me some extreme programming feel where I am building my own game by creating expansions for the core game. Once I'm done with the core game, anyone else can expand the game again using the same process - simply listen for or post network messages on the various channels in use by a given peer mesh. The only time you would need to recompile the game client or the universe server is if you added new message types and wanted to add functionality to the existing game that wasn't there before.
All in all, I'm pretty excited about it and my next UA-related post will be a demo of me integrating the previous work on NPC workflows with my network engine so that I've got functioning NPCs that are spitting out periodic radar pings based on their own WF program instances.
Nice work and great explanation. Looking forward to your next post.