301 Days

A year of gamedev experiments.

Day 70b - Player Data

| Comments

In which we fix a couple of trivial bugs, finding some misplaced info.


Fix a Bug in the Legacy Code Every Fifth Day

Here’s an easy one: the game server name, though configurable via APP_NAME, is harcoded in a few of the menus. A relatively trivial fix, I would hope.

DragonsSpine/Menus/Menu.cslink
85
ch.WriteLine(DragonsSpineMain.APP_NAME + " ("+DragonsSpineMain.APP_VERSION+") Character Menu");

Yes, completely trivial. More of an oversight than a bug, really; since this code only ran on one server that I’m aware of, the configurability of the name need not be a priority.

Maybe a little less trivial:

features/config_file.featurelink
143
144
145
146
147
148
149
150
151
152
153
154
# bug - server fails trying to retrieve 'anonymous' field from the Player table, should be checking
#       PlayerSettings table.
@bug
Scenario: APP_NAME used in high score list
  Given I use the "minimal" database as-is
 And I set "APP_NAME" in the config file to "Test HigSco"
 And the server executable is started
 And I allow time for the server to complete startup
 When I log on using a standard account
 And I enter the chat
 And I issue the high scores command
 Then I saw a high score list with application name "Test HigSco"

The bug doesn’t have much to do with this test, but the server does a check to exclude anonymous players from the high score list:

DragonsSpine/DAL/DBWorld.cslink
491
492
493
score = new PC();
score.PlayerID = Convert.ToInt32(dr["playerID"]);
score.IsAnonymous = (bool)PC.GetField(score.PlayerID, "anonymous", score.IsAnonymous, null);

Unfortunately PC.GetField looks directly in the Player table, which doesn’t actually have an anonymous field any more. But there’s a helpful method to figure out which table the field is in:

DragonsSpine/DAL/DBPlayer.cslink
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
internal static string getPlayerTableName(int playerID, string field) // gets the table name that contains player field
{
    try
    {
        string[] tableNames = {"Player", "PlayerSettings"};

        SqlStoredProcedure sp;
        for (int a = 0; a < tableNames.Length; a++)
        {
            sp = new SqlStoredProcedure("prApp_" + tableNames[a] + "_Select", DataAccess.GetSQLConnection());
            sp.AddParameter("@playerID", SqlDbType.Int, 4, ParameterDirection.Input, playerID);
            DataTable dt = sp.ExecuteDataTable();
            foreach (DataColumn dc in dt.Columns)
            {
                if (dc.ColumnName == field) {
                    Utils.Log("DBPlayer.getPlayerTableName(" + playerID + ", " + field + ") found field in table " + tableNames[a] + ".", Utils.LogType.Info);
                    return tableNames[a];
                }
            }
        }
        Utils.Log("DBPlayer.getPlayerTable(" + playerID + ", " + field + ")  Field was not found in any player table.", Utils.LogType.SystemFailure);
        return "error";

    }
    catch (Exception e)
    {
        Utils.LogException(e);
        return "error";
    }
}

(I added the debug at line 42 so that I could verify my fix.) This getPlayerTableName method is used by the getPlayerField method, so if we just switch to that we’ll be fine:

DragonsSpine/DAL/DBWorld.cslink
493
494
score.IsAnonymous = (bool)DBPlayer.getPlayerField(score.PlayerID, "anonymous", score.IsAnonymous.GetType());
            // was: (bool)PC.GetField(score.PlayerID, "anonymous", score.IsAnonymous, null);

The interesting bit here is the getPlayerTableName method. It can be assumed that the Player table was once even more monolithic, and an effort was undertaken to move things out of it. While that was underway, access was channeled through methods which check multiple tables for a field. There was an efficiency hit due to additional database calls, but perhaps this was considered the safest way to proceed.

I’ve certainly written similar things; additional complexity to keep things safe while I reworked major sections. In my more test-driven development work, I’ve gotten away from this entirely; the tests keep me safe, and I refactor with wild abandon.

That’s the kind of freedom that should make working on the new server-side code very exciting. Tomorrow.


Useful Stuff


Day 70b code - tests Day 70b code - server

Comments