Skip to main content
  1. Posts/

Day 70b - Player Data

OldDays drag-spin-exp csharp cucumber

Player data access.
Player data access.

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.cs
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.feature
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.cs
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.cs
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.cs
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
#


More to come
More to come

Day 70b code - tests

Day 70b code - server