Thought I would go ahead and post a little about the architecture I have set up for my PBBG engine so far. Basically, the engine is a library that other projects can reference to make building PBBGs a little easier. All of the logic for handling incoming requests and parsing commands is contained within the engine. My PBBG engine is kind of like a MUD driver, it requires a MUDLib to define objects, persist data, etc. Some interfaces are defined within the engine library to make it extensible while it also contains base class implementations of those interfaces to make building on top of working logic possible. When the engine starts up it raises a set of events and when it processes commands it also raises events to allow the implementing application to control loading of commands, determining the server implementation and creating command instances.
Not the best diagram in the world but kind of gives you the idea of how it works. The column down the middle are the interfaces defined by then engine, which also define base classes, except for the CommandManager which is just a static class for processing commands.
In addition to the classes here are the Verb abstract class, the ICommand interface and the Command<Verb> instance for creating commands from Verbs. The CommandManager raises an event when it finds the command text that allows an external library to set the ICommand instance that will execute the current command. When the engine starts up though it raises an event that will allow the implementation library to set all the commands into memory rather than creating a new instance with each command.
The IServer interface defines an IConnectionManager property where connections into the server are managed, either socket or http.
On the NET side, which is actually a namespace ".Net"; the "Server" instance actually contains the socket used to listen for incoming connections on a port specified during startup. From there the individual IConnection instances contained in the IConnectionManager instance handle processing the input and formatting it into a command. The IConnection instance contains the connected socket and will send the command to the CommandManager.
Both IConnection instances in both namespaces allow messages to be sent to the client along with custom data such as stats, gold, map data, etc. The difference between the two is that the WEB instance sends all of this back as JSON in the HTTP response and the NET instance sends the messages down the socket as they are added to the IConnection instance and then sends the additional data once the command completes execution.
That is all I have completed at this point on the engine side, it processes commands from the web and the implementation library sitting on top of it handles the commands and persists the data. There is plenty of work on the implementation library side still yet to be completed.
I haven't decided yet but am considering using Silverlight 2.0 with the next release of Perenthia. I've completed a good portion of my PBBG engine that will drive Perenthia but want to be able to take advantage of some the features of Silverlight 2.0 to provide better user experience. One of the features that really interests me is the socket support for 2.0. Once I get the 2.0 beta 1 bits I am going to start playing around with running my PBBG engine on a socket server application I wrote for Flash. If all goes well I should be able to provide some better multiplayer features in Perenthia such as real time chat and possibly player vs player combat.
Perenthia will still primarily be a text-based game but Silverlight could allow me to bridge the gap between web and client software.
|From the moment you came into our home you were always daddy's buddy. We would sit in my chair and watch TV and you always helped me out in the garage when I was working on something for mommy.|
|You loved to be "The Ranger" when we went out back or to the park. You would run ahead on trails; exploring and taking in all the sights and smells of the forest.|
|You and Sydney loved "Playtime" out back, especially in the snow. She loved chasing you around the yard and loved being chased.|
|You had a gentle soul and an overabundance of patience with the smaller residents of our home. Always easy going and always happy to have a comfortable place to nap.|
I know I will see you again someday but until that time I will hold your memory in my heart and all the joy you brought to our home. Rest in peace Clifford, you will always be "daddy's bestest buddy".
I might have mentioned it before but my PBBG engine is basically a commands processor. In other words it accepts commands from the client, processes the information on the server and sends the response back to the clients as JSON. Not really different from a normal web request except it is specific to my PBBG engine and you don't request documents from the server you are telling the server you want your Character to "do" something.
My PBBG engine is essentially just the command processor and the classes surrounding processing commands. I have abstracted it completely from the data source. There are no data providers or data connections at all in the engine. Instead, if it needs to get data it raises events that a deriving library can handle and pass back the required data in the form of simple interfaces. Some assumptions I did make such as ID values defined in interfaces are int values rather than object since I don't design databases with primary keys other than int. :)
One of the things I also did for the CommandManager was to created an abstract Verb class that I can derive from to create command verbs such as move, say, attack, etc. These command verbs can be defined in the deriving library and set in the CommandManager when the game starts up. Another class to assist with commands was a generic Command<T> class where T has to be a derived Verb value. So I can create Command<Move>() and the call an Execute method on the class which in turn creates the Verb instance and executes the code in the Verb class.
This has been working pretty well so far and since the CommandManager raises an event each time if processes a command I can have any number of derived libraries executing their own commands.
Perenthia currently provides "wilderness" areas where monsters roam around waiting to attack players who wander beyond the safety of the towns. I had originally wanted the wilderness to auto generate instead of how it works now where all the wilderness "tiles" are stored in the database. This caused over 150,000 records to have to be entered into the table and really limits expanding the word since I have to basically draw all the tiles.
For the Perenthia Beta 2 I worked out a "Regions" table to store a rectangle x,y,z value. The Regions table also stores the min and max levels required to venture into the region. Towns located within regions also carry a safe indicator so that monsters will not auto generate. Using this concept I only have to create the towns or places of importance and can let the "wilderness" be auto generated.
The auto generated wilderness is infinite in that each wilderness place visited is created and stored on the player record. Wilderness is also exclusive to the player so that monsters generated will be available only to the adventurer. A lot of games have done this with dungeon instances and I thought it was a good idea to implement in Perenthia. There will be ways to interact with others and I still have some work to do to handle group play but wilderness is intended for solo players. Now, given that wilderness is infinite I don't want players getting lost so, the last non-wilderness place they visit will be stored on their player record and if they log out and log back in they will be reset to the previous non-wilderness place. It's kind of a fast way to cheat your way back to town if you get into trouble but I am OK with that. I would rather players leap back to town before their character dies than wander aimlessly around thousands of tiles from civilization. I want the wilderness adventuring to be a fun way to earn gold, not a potential for grief.
Quests may require adventuring through the wilderness to find hidden places so logging out when you are in trouble will cause your quest to take even longer. I think this will be a good trade off because quests will offer greater rewards than adventuring and should require a higher level of mastery.
Spent some time today working on the UI for Perenthia. For now it will remain AJAX based but in the future I will probably add a Silverlight front end as well. I will post some screenshots of it soon, I want to get the layout complete first.
I also spent some time working through my data model for quests. I still need to do some work but I think it will be flexible enough to allow for adding all manner of quests and adventures.