Login | Register  
Viewing Category

Current Articles | Categories | Search | Syndication


Source Code

    Loading game data from the document database (RavenDb)

     940 Views ::  0 Comments :: Categories: Source Code, MUD Server

    Loading custom game data from the document database is not much harder than saving it. The hardest part has been creating the indexes to retrieve documents. These indexes can be thought as stored procedures. One really nice thing about RavenDb is that it lets you check if these indexes are there, if not, then create them. Here's the code for the index that I'm currently using: 

    /// <summary>

    /// Creates the needed indexes, if they don't exist.

    /// </summary>

    public static void CreateIndexes()

    {

        var store = Instance;

     

        store.DatabaseCommands.PutIndex(

            "GetPlayerByDatabaseId",

            new IndexDefinitionBuilder<PlayerDocument>

            {

                Map = docs => from doc in docs

                              select new

                              {

                                  doc.DatabaseId

                              }

            });

    }

    That DatabaseId is to match the document being saved to the player's settings in the database. It keeps things tidy.

    posted @ Tuesday, May 24, 2011 12:24 PM by Fastalanasa

    Saving game data to document database (RavenDb)

     776 Views ::  0 Comments :: Categories: Source Code, MUD Server

    WheelMUD can now save custom gaming data to the document database (RavenDb). This makes it extremely easy to deal with changing requirements for custom gaming systems. There is no relational database schema to fight with. You can pass an object, and it's internal representation will saved as a JSON text document on disk.

    I did run into some interesting caveats. You have to be careful in what you try to save. You won't be able to save objects that self-reference. The Thing class had a few properties that were of the Thing type. At first I just tried to decorate these with the JsonIgnore attribute. That didn't quite work in my case, because of how the inheritance chain was setup. I ultimately went with a generic class with all the stuff that I wanted to save. This is now the PlayerDocument class. It makes it very easy to deal with.

    This is now working consistently. We have player settings saving to the SQLite database, and gaming data saving to the document database. I really like this hybrid approach as it makes the best use of these two technologies. No more trying to shoehorn a non-relational model onto non-relational data.

    Here is the code in WheelMUD.ConnectionStates.CreationState that actually does the saving: 

     

    // Save to the document database

    using (var ravenSession = DalUtils.GetRavenSession())

    {

        var bundle = new PlayerDocument

            {

                Behaviors = this.Session.Thing.BehaviorManager.ManagedBehaviors,

                DatabaseId = pb.PlayerData.ID,

                Name = newCharacter.Name,

                LastUpdatedDate = currentTime,

                Stats = this.Session.Thing.Stats,

                GameAttributes = this.Session.Thing.SecondaryStats,

                Skills = this.Session.Thing.Skills,

                SubThings = this.Session.Thing.SubThings

            };

     

        ravenSession.Store(bundle);

        ravenSession.SaveChanges();

    }

     

    posted @ Tuesday, May 24, 2011 12:18 PM by Fastalanasa

    Genders in WheelMUD

     890 Views ::  0 Comments :: Categories: Source Code, MUD Server

    I made a new class called Gender in the WheelMUD.GameEngine namespace. I always felt uncomfortable with hard-coded genders. I created a data and parser files for Warrior, Rogue, and Mage (WRM). These load into the GameSystemController.Genders dictionary. I thoght this was a more flexible way of doing this. The WRM character creation step that picks genders has been modified to use this new functionality.

    My main reason behind this was to support gaming environments that support more than the binary male/female choices. Science fiction has races that have alternate gender arrangements. You have the Andorians in Star Trek that have 4 genders. There are several species in several universes that are hermaphrodites.

    While I believe that genders are not necessary for gaming, they do bring interesting prospects for game character development, and can add depth to game play.

    /// <summary>

    /// This represents a player, Mob, or NPC gender.

    /// </summary>

    public class Gender

    {

        /// <summary>

        /// Initializes a new instance of the <see cref="Gender"/> class.

        /// </summary>

        /// <param name="name">The name for this gender.</param>

        /// <param name="displayName">The display name for this gender.</param>

        public Gender(string name, string displayName)

        {

            this.Name = name;

            this.DisplayName = displayName;

        }

     

        /// <summary>

        /// Gets the name for this gender.

        /// </summary>

        public string Name { get; private set; }

     

        /// <summary>

        /// Gets the display name for this gender.

        /// </summary>

        public string DisplayName { get; private set; }

    }

    posted @ Tuesday, May 24, 2011 12:04 PM by Fastalanasa

    Skills in WheelMUD

     885 Views ::  0 Comments :: Categories: Source Code, MUD Server

    Currently the skills are on the Thing class as a list of GameEngine.GameSkill. I keep going back and forth between making skills into a SkillsBehavior or a list of GameSkills. I'm very sure that how to do this will be apparent once we start working on the game basic actions.

    The Warrior, Rogue, and Mage (WRM) list of skills are now being loaded into the gaming engine, and are available to the rest of the MUD framework. The WRM character creation system now lets players select their skills. These are now being saved to the document database. I'm working on getting these loading once a player logs back in. Currently stuck on a circular reference loop. 

    /// <summary>Gets a dictionary of the game skills that apply to this thing.</summary>

    public Dictionary<string, GameSkill> Skills

    {

        get

        {

            lock (this.lockObject)

            {

                return this.skills;

            }

        }

    }

    posted @ Tuesday, May 24, 2011 11:56 AM by Fastalanasa

    Gaming Systems - Stats

     1107 Views ::  0 Comments :: Categories: Source Code, .NET, MUDs

    I'm very excited about this latest bit of code and data that I checked in today. I fixed the stats so that they load a template from whatever gaming system is currently setup to run. First let me enumerate the systems that I tested with today:

    • Dungeons and Dragons 4th Edition Quick Start
    • GURPS Lite - Generic system, can literally run any genre
    • PathFinder - D&D 3rd edition clone
    • ShadowRun - Magic and SciFi together
    • The Artifact - Science Fiction
    • Warrior, Rogue, and Mage - Very simple fantasy system

    I got the stats loading for each one. Here are screen captures for each:

    Dungeons and Dragons 4th Edition Quick Start

    GURPS Lite

    PathFinder

    ShadowRun 3rd Edition

    The Artifact

    Warrior, Rogue, and Mage

    As you can see, I have the stats for all of these 5 gaming systems loading. It was relatively painless to do this. It took me about 15 minutes per new gaming system to get the stats up and running. Here are the steps:

    1. Navigate to the Files\GameRules directory
    2. Create a directory to hold your new game system's content
    3. Create a Data and Parsers directories under this root directory
    4. Create a XML file to hold the stat information, and put it in the Data directory
    5. Create a C# parser file, and put it in the Parsers directory
    6. Create a master xml file and place it in the Files\GameRules directory
    7. Adjust the contents of the master file to point to the root game directory
    8. Modify the mud.config file for the new system

    Here's a screen capture of the region of the mud.config file that we need to change:

    The values above will run The Artifact rules. The most important key here is "masterfile" that will tell WheelMUD which system to pick up. The "currentruleset" value is a human readable label that will be used in WheelMUD for admins and builders.

    My main push behind this, is so that I can start figuring out how to do basic combat. I really want to get the core systems working ASAP. I will be moving a lot of stuff off the 0.5 task list, so that we can concentrate on core stuff. The first casualty will be the remote admin stuff. That's just distracting me completing the core systems, which is what we all want to get done.

    posted @ Saturday, April 30, 2011 7:05 PM by Fastalanasa

    RavenDB - More lessons learned

     1166 Views ::  0 Comments :: Categories: Source Code, .NET

     I've been fiddling around with the Behaviors saving and loading using RavenDB. Here's what I learnt... The best strategy is to let RavenDB do what it is good at, which is to store and load documents to/from disk. I was trying to save a dictionary to disk, and running into casting exceptions when converting the dictionary in JSON format to the actual dictionary object. The best strategy, so far, is to save the actual derived Behavior instead. So I've been saving PlayerBehaviors. These load fine, and I don't have to tweak the code to do custom work.

    To load the PlayerBehavior documents, I'm issuing this LINQ query:

    List<PlayerBehavior> playerBehaviors = session.Query<PlayerBehavior>().ToList();

    For saving I'm using this code:

    using (var session = DALUtils.GetRavenSession())
    {
          session.Store(this);
          session.SaveChanges();
    }

        public class DocumentStoreSingleton
        {
            private static EmbeddableDocumentStore _instance;

            public static EmbeddableDocumentStore Instance
            {
                get
                {
                    if (_instance == null)
                    {
                        _instance = new EmbeddableDocumentStore { DataDirectory = DALUtils.GetDbPath() };
                        _instance.Initialize();
                    }

                    return _instance;
                }
            }
        }

            public static IDocumentSession GetRavenSession()
            {
                var store = DocumentStoreSingleton.Instance;

                var session = store.OpenSession();

                return session;
            }

    The RavenDB team has recommended to make the call to the DocumentStore a singleton. That works well.

    I've included a zip with the binaries for this spike. You will be able to create "players" and load them into the UI. You will need .NET 4.0 installed. The source is not ready for distribution, since I would have to copy all the needed assemblies locally.

    Attachments:

    posted @ Sunday, January 09, 2011 6:45 PM by Fastalanasa

    RavenDB & WheelMUD - Take 2

     1143 Views ::  0 Comments :: Categories: Source Code, .NET

    Breakthrough! I finally figured out how to do simple indexes in RavenDB. In hindsight, the answer was staring me in the face. It only took me to look at this when I had a rested mind. Here's a LINQ query to get the PlayerBehavior by name:

    from doc in docs
    where doc["@metadata"]["Raven-Entity-Name"] == "PlayerBehaviors"
    select new { doc.Name }

    To query this just issue this command on the Web UI:

    Name:crashtestdummy

    The playerbehavior document JSON looks like this:

    {
        "Name":"CrashTestDummy",
        "Password":"dummy",
        "Gender":"Female",
        "TimeInstantiated":"12/5/2010 10:27:44 PM"
    }

    You have to make sure that the property you are quering against is typed exactly as it is typed in the document. Notice that Name has an uppercase N. These things are case sensitive.

    My next step is to get this working from C# code.

    posted @ Tuesday, December 14, 2010 10:02 AM by Fastalanasa

    RavenDB & WheelMUD - Take 1

     1070 Views ::  3 Comments :: Categories: Source Code, .NET

    I spend a few hours learning how to use RavenDB yesterday. I first read through the tutorials and documentation on the home page for RavenDB. Unfortunately, the docs are way out of date, as the codebase for RavenDB appears to be moving and changing rapidly.

    The first hurdle was that the documentation doesn't explain what namespaces are needed to use for what functionality. This seems to be a frequent problem an 3rd party APIs. I'm specifically testing the embedded stuff. I used the latest build, which is RavenDB-Build-206.

    Here's how you setup saving:

           using Raven.Client.Client;

            public void Save()
            {
                var store = new EmbeddableDocumentStore { DataDirectory = DALUtils.GetDbPath() };
                store.Initialize();

                var session = store.OpenSession();
                session.Store(this);
                session.SaveChanges();
                session.Dispose();
            }

    My take-away from this code is that saving to the datastore is EXTREMELY easy. So the steps for saving are:

    1. Create an EmbeddableDocumentStore.
    2. Give it the path you want it to create the document files in.
    3. Initialize the data store.
    4. Create a session.
    5. Use the session to actually store. Note that this does not actually save the current document.
    6. Save the changes.
    7. This is optional, but always a good idea, dispose of the session.

    Now the hard part, at least to me, is retrieving this back. I have been able to look at the actual document that got stored. I used that knowledge to write a simple function that loads thae class document from disk. The raw JSON for this document looks like this:

    {
        "Name":"CrashTestDummy",
        "Password":"dummy",
        "Gender":"Male",
        "TimeInstantiated":"12/5/2010 10:27:44 PM"
    }

    The properties were declared like this:

        public enum GenderTypes
        {
            Male,
            Female,
            Neuter
        }

            /// <summary>
            /// Gets or sets the name.
            /// </summary>
            /// <value>The name for this player.</value>
            public string Name { getset; }

            /// <summary>
            /// Gets or sets the password.
            /// </summary>
            /// <value>The password.</value>
            public string Password { getset; }

            /// <summary>
            /// Gets or sets the gender.
            /// </summary>
            /// <value>The gender.</value>
            public GenderTypes Gender { getset; }

            /// <summary>
            /// Gets or sets the time instantiated.
            /// </summary>
            /// <value>The time instantiated.</value>
            public string TimeInstantiated { getset; }

    The metadata is this:

    {
        "Content-Encoding":"gzip",
        "Raven-Entity-Name":"PlayerBehaviors",
        "Raven-Clr-Type":"Behaviors.PlayerBehavior, Behaviors"
    }

     Loading this dynamically like I do from databases has eluded me. You normally would use a LINQ query to get the object. These three queries work:

    from doc in docs
    where doc.Name == "CrashTestDummy"
    select new { doc.Name }

    from doc in docs
    where doc.Name == "CrashTestDummy"
    select doc

    from doc in docs
    where doc["@metadata"]["Raven-Entity-Name"] == "PlayerBehaviors"
    select doc

    What is baffling me specifically, is how to create an index that I can query against. I got the queries above, after I read an entry in the ravendb Google Groups.

    The previous version of the save code, just saved the properties stored in a dictionary. So the old document looks like this:

    {
        "Id":"57b7b3a0-ad7b-46e1-bb92-d0bb879d6522",
        "Name":"CrashTestDummy",
        "Password":"dummy",
        "Gender":"Male"
    }

    The metadata is this:

    {
        "Content-Encoding":"gzip",
        "Raven-Entity-Name":"DictionariesOfStringsOfStrings",
        "Raven-Clr-Type":"System.Collections.Generic.Dictionary`2[]System.String, mscorlib[]System.String, mscorlib[], mscorlib"
    }

    So to load this I did this:

            public Dictionary<stringstring> Load(string playerName)
            {
                var session = _store.OpenSession();

                var playerProperties = session.Load<Dictionary<stringstring>>("dictionariesofstringsofstrings/1");

                session.Dispose();

                return playerProperties;
            }

    I haven't changed this to work with the new save method, which uses the actual PlayerBehavior class for saving.

    So this is as far as I've gotten by myself. I'm going to need to post some questions on the ravendb Google Groups, to move me forward from my current rut.

    The management UI is not out yet, but I did find a workaround. RavenDB comes with a built-in server. I copied the data folder into the Data folder that sits on the same directory as Raven.Server.exe. This is a minuature web server. Once you start this server, you point your browser to http://localhost:8080 to see the web UI. That was good enough to let me examine the documents.

    Anyways, I'm pretty tired, so I'm going to stop here.

    posted @ Monday, December 06, 2010 11:32 PM by Fastalanasa

    Using NCalc for RuleSets

     875 Views ::  0 Comments :: Categories: Source Code

    I'm finally getting around to doing code spikes with NCalc and RuleSets. I created a quick throwaway app to test a simple formula.

    Notice the brackets around DieRoll and ST. Those denotes an NCalc parameters. The parameters work a lot like ADO.NET. Here's the snippet that actually does the hard work:

    var exp = new Expression(txtFormula.Text);
    exp.Parameters["ST"] = int.Parse(txtST.Text);
    exp.Parameters["DieRoll"] = dieTotals;string result = exp.Evaluate().ToString();

    This formula is a GURPS Lite success roll. Since this is a boolean formula, you will get True or False. You can change the formula or the values and re-evaluate the formula without having to restart the program. That is pretty cool!

    Now that I have an idea of how this works, I will next move on how to do this dynamically. In the context of NCalc, RuleSets look like will need some very clear definitions. I'm guessing that there will have to be a table that will have one row for the formula, and another row that contans a list of parameters with some sort of separator (undetermined at this point). I sat down with my brainstorm notebook, and I came up with ToHitFormula, DamageFormula, InitiativeFormula, and several others. These, and some more, will be the required rules. I haven't figured out to do custom rules yet. So far, I see that this setup will allow for a LOT of flexibility. You should be able to edit these formulas in game, without having to reload the game.

    I've included this solution in a zip file. This is a Visual Studioi 2010 solution. I'm pretty sure some of you will want to play with this.

    Attachments:

    posted @ Monday, September 20, 2010 8:40 PM by Fastalanasa

    WheelMUD and SharpDevelop 4.0

     1272 Views ::  0 Comments :: Categories: Source Code, .NET, MUDs

    I just wanted to show everybody that SharpDevelop 4.0 is a good IDE to work with WheelMUD. Here are some screenshots of me running WheelMUD from SD4:

    posted @ Friday, August 20, 2010 7:53 PM by Fastalanasa

    Page 1 of 5First   Previous   [1]  2  3  4  5  Next   Last   
    Copyright 2007-2012 by WheelMUD  | Terms Of Use | Privacy Statement
    Google Analytics Alternative