301 Days

A year of gamedev experiments.

Day 47 - Minimalism

| Comments

“It’s a small world, after all.” – The Sherman Brothers

A Bear of Very Little Brain

I don’t intend to write unit tests for the existing code, which means every little piece of functionality I test will mean spinning up the full game server. For the sake of both time and resources, we’ll want to minimize the footprint of the server however we can (while still running a valid test). Let’s see just how small we can make it:

Server Requirements

  1. The server executable.
  2. The configuration file.
  3. The database.
  4. The map file(s).
  5. Two network ports.

We’re not going to make the executable any smaller, the config file is already pretty minimal, and the network ports are pretty non-negotiable (although we may/must move them to run tests in parallel). That leaves us with the database and map files (and the subsequent memory usage based on their contents).

Minimal Database

Let’s do some experiments:

  • First, we start it up with the standard DB we’ve been using:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
6/2/2016 8:52:08 PM: {SystemGo} Drag Spin Exp 2.0.99.5
> 6/2/2016 8:52:08 PM: {SystemGo} Compiling scripts.
> 6/2/2016 8:52:09 PM: {SystemGo} Compiled!
> 6/2/2016 8:52:10 PM: {SystemGo} Added Facet: Agate
> 6/2/2016 8:52:10 PM: {SystemGo} Added Land: Beginner's Game to Facet: Agate
...
> 6/2/2016 8:52:10 PM: {SystemGo} Loaded Map: Island of Kesmai
...
> 6/2/2016 8:52:11 PM: {SystemGo} Loaded Cell Info for Island of Kesmai...
...
> 6/2/2016 8:52:20 PM: {SystemGo} Loaded Quest: Ironbar's Black Broadsword
...
> 6/2/2016 8:52:20 PM: {SystemGo} Loaded SpawnZones (369)...
> 6/2/2016 8:52:20 PM: {SystemGo} Clearing PC Location Data.
> 6/2/2016 8:52:20 PM: {SystemGo} Loaded Spells (65) ...
> 6/2/2016 8:52:20 PM: {SystemGo} Clearing NPC Location Data.
> 6/2/2016 8:52:20 PM: {SystemGo} Creating NPC Catalog.
> 6/2/2016 8:52:20 PM: {SystemGo} Loaded NPCs (438)...
> 6/2/2016 8:52:20 PM: {SystemGo} Spawning NPCs.
> 6/2/2016 8:52:22 PM: {SystemGo} Restocked 0 store records.
> 6/2/2016 8:52:22 PM: {SystemGo} Master round timer started.
> 6/2/2016 8:52:22 PM: {SystemGo} Save timer started.
> 6/2/2016 8:52:22 PM: {SystemGo} Janitor round timer started.
> 6/2/2016 8:52:22 PM: {SystemGo} Chronology timer started.
> 6/2/2016 8:52:22 PM: {SystemGo} Lunar cycle timer started.
> 6/2/2016 8:52:22 PM: {SystemGo} Inactivity timer started.
> 6/2/2016 8:52:22 PM: {SystemGo} Listening for connections on port 3000.
> Protocol Server listening to port 4000.
6/2/2016 8:52:22 PM: {SystemGo} Starting main game loop.
>

On my main dev machine, that’s 14 seconds to start up. After a bit of settling, it’s using about 360mb of memory for the server executable.

  • Now let’s export the DB to a script and whittle down some of those tables:
1
2
06/02/2016  00:01 AM        56,732,419 EntireDB-initial.sql
               1 File(s)     56,732,419 bytes

56mb? This will take some doing.

  • Table: Accounts

    Just one will do.

  • Tables: BannedIP, EffectTypeCode, Mail, MailAttachment, Zones
    • Already empty.
  • Table: CatalogItem
    • 382 rows, let’s make that one: A small rock, catalogID 239.
  • Table: Cell
    • 132 rows, let’s make that one: just the spawn point on the Island.
  • Table: CharGen
    • 40 rows of races and classes. Remove all but Fighter Barbarian.
  • Table: Facet
    • Already only one entry.
  • Table: Land
    • Three entries: Beginner’s Game, Advanced Game, and Underworld. Now just Beginner’s.
  • Tables: LiveCell, LiveNPC, LivePC, NPCLocation
    • These are populated at runtime, make them initially empty. I’ll bet that cuts down the script size a bit.
  • Table: Map
    • Only the Island; not loading any other maps should help quite a bit.
  • Table: NPC
    • 438 rows, let’s make that one: the Kesmai Dog.
  • Table: Player*
    • Cut down to the same one as in Accounts. Many of these need a set of empty entries for each player.
  • Tables: Quest, Spells, Stores
    • Empty them out, let’s see if that’s tolerated.
  • Table: SpawnZone
    • 369 rows, cut it down to just Kesmai Dog.
  • Table: World
    • Only one row with some of the server settings? Just edit the name for now.
1
2
06/02/2016  00:01 PM        56,732,419 EntireDB-initial.sql
06/02/2016  01:01 PM           240,406 EntireDB-snip01.sql

Well, that’s certainly a difference. Can I still set up a working database with the new file?

Ironing out the Kinks

1
K:\301days\Code\seitan-spin>sqlcmd -U sa -P "password" -S "localhost\MYTESTSQL" -i EntireDB-snip01.sql

Bad Segue

1
2
Msg 208, Level 16, State 1, Server BARBALOOT\MYTESTSQL, Procedure Segue_VIEW, Line 4
Invalid object name 'dbo.Segue'.

Hmm, none of my DBs even have a Seque table. Heading back to the source material, there is an SQL script to create it. So let’s add that in and see what’s next.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
Msg 207, Level 16, State 1, Server BARBALOOT\MYTESTSQL, Procedure Segue_VIEW, Line 5
Invalid column name 'Map1ID'.
Msg 207, Level 16, State 1, Server BARBALOOT\MYTESTSQL, Procedure Segue_VIEW, Line 6
Invalid column name 'Land2ID'.
Msg 207, Level 16, State 1, Server BARBALOOT\MYTESTSQL, Procedure Segue_VIEW, Line 3
Invalid column name 'Land1ID'.
Msg 207, Level 16, State 1, Server BARBALOOT\MYTESTSQL, Procedure Segue_VIEW, Line 3
Invalid column name 'Map1ID'.
Msg 207, Level 16, State 1, Server BARBALOOT\MYTESTSQL, Procedure Segue_VIEW, Line 3
Invalid column name 'Land2ID'.
Msg 207, Level 16, State 1, Server BARBALOOT\MYTESTSQL, Procedure Segue_VIEW, Line 3
Invalid column name 'Map2ID'.
Msg 207, Level 16, State 1, Server BARBALOOT\MYTESTSQL, Procedure prApp_Segue_Update, Line 18
Invalid column name 'Land1ID'.
Msg 207, Level 16, State 1, Server BARBALOOT\MYTESTSQL, Procedure prApp_Segue_Update, Line 19
Invalid column name 'Map1ID'.
Msg 207, Level 16, State 1, Server BARBALOOT\MYTESTSQL, Procedure prApp_Segue_Update, Line 22
Invalid column name 'Land2ID'.
Msg 207, Level 16, State 1, Server BARBALOOT\MYTESTSQL, Procedure prApp_Segue_Update, Line 23
Invalid column name 'Map2ID'.
Msg 207, Level 16, State 1, Server BARBALOOT\MYTESTSQL, Procedure prApp_Segue_Select2, Line 13
Invalid column name 'Land2ID'.
Msg 207, Level 16, State 1, Server BARBALOOT\MYTESTSQL, Procedure prApp_Segue_Select2, Line 14
Invalid column name 'Map2ID'.
Msg 207, Level 16, State 1, Server BARBALOOT\MYTESTSQL, Procedure prApp_Segue_Select1, Line 13
Invalid column name 'Land1ID'.
Msg 207, Level 16, State 1, Server BARBALOOT\MYTESTSQL, Procedure prApp_Segue_Select1, Line 14
Invalid column name 'Map1ID'.
Msg 207, Level 16, State 1, Server BARBALOOT\MYTESTSQL, Procedure prApp_Segue_Select, Line 9
Invalid column name 'Land1ID'.
Msg 207, Level 16, State 1, Server BARBALOOT\MYTESTSQL, Procedure prApp_Segue_Select, Line 10
Invalid column name 'Map1ID'.
Msg 207, Level 16, State 1, Server BARBALOOT\MYTESTSQL, Procedure prApp_Segue_Select, Line 13
Invalid column name 'Land2ID'.
Msg 207, Level 16, State 1, Server BARBALOOT\MYTESTSQL, Procedure prApp_Segue_Select, Line 14
Invalid column name 'Map2ID'.
Msg 207, Level 16, State 1, Server BARBALOOT\MYTESTSQL, Procedure prApp_Segue_Insert, Line 16
Invalid column name 'Land1ID'.
Msg 207, Level 16, State 1, Server BARBALOOT\MYTESTSQL, Procedure prApp_Segue_Insert, Line 16
Invalid column name 'Map1ID'.
Msg 207, Level 16, State 1, Server BARBALOOT\MYTESTSQL, Procedure prApp_Segue_Insert, Line 16
Invalid column name 'Land2ID'.
Msg 207, Level 16, State 1, Server BARBALOOT\MYTESTSQL, Procedure prApp_Segue_Insert, Line 16
Invalid column name 'Map2ID'.

Well, that’s interesting. Time to poke into the server code and see if Seque is even used. Most of these procedures are never referenced, but…

"DragonsSpine/DAL/DSpineDB.cs"link
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
        internal static int InsertSegue(int Land1,int Map1,int yCord1,int xCord1,int Land2,int Map2,int yCord2,int xCord2,int height)
        {
            try
            {
                SqlStoredProcedure sp = new SqlStoredProcedure("prApp_Segue_Insert", DataAccess.GetSQLConnection());
                sp.AddParameter("@Land1ID",     SqlDbType.Int,      4,  ParameterDirection.Input, Land1);
                sp.AddParameter("@Map1ID",      SqlDbType.Int,      4,  ParameterDirection.Input, Map1);
                sp.AddParameter("@Ycord1",      SqlDbType.Int,      4,  ParameterDirection.Input, yCord1);
                sp.AddParameter("@Xcord1",      SqlDbType.Int,      4,  ParameterDirection.Input, xCord1);
                sp.AddParameter("@Land2ID",     SqlDbType.Int,      4,  ParameterDirection.Input, Land2);
                sp.AddParameter("@Map2ID",      SqlDbType.Int,      4,  ParameterDirection.Input, Map2);
                sp.AddParameter("@Ycord2",      SqlDbType.Int,      4,  ParameterDirection.Input, yCord2);
                sp.AddParameter("@Xcord2",      SqlDbType.Int,      4,  ParameterDirection.Input, xCord2);
                sp.AddParameter("@Height",      SqlDbType.Int,      4,  ParameterDirection.Input, height);


                return sp.ExecuteNonQuery();
            }

And yet that code is never called. So it looks like it’s safe to remove the Seque stuff from the DB entirely.

More Trouble

1
2
3
4
5
6
7
8
9
Msg 207, Level 16, State 1, Server BARBALOOT\MYTESTSQL, Procedure NPC View, Line 3
Invalid column name 'ArmorType'.
Msg 207, Level 16, State 1, Server BARBALOOT\MYTESTSQL, Procedure NPC View, Line 3
Invalid column name 'DB'.
Msg 207, Level 16, State 1, Server BARBALOOT\MYTESTSQL, Procedure NPC View, Line 3
Invalid column name 'OB'.
Msg 207, Level 16, State 1, Server BARBALOOT\MYTESTSQL, Procedure NPC View, Line 3
Invalid column name 'Hits'.
etc...

NPC has a lot of fields, but not the ones NPC View is looking for. And, surprise, it’s not used in the server code. Looking further, similar issues with Items Attack and Block Ranks, Item Loot View, prApp_Spells_Update, etc. Let’s just scrape those out of the SQL script, and then finally we have something we can use, right?

Server Acid Test

The only thing to do now is to point the server at this minimal DB and start it up.

1
2
3
4
6/3/2016 1:01:58 AM: {SystemFailure} Failure in JanitorEvent while pruning cells.
6/3/2016 1:02:08 AM: {SystemFailure} Failure in JanitorEvent while pruning cells.
6/3/2016 1:02:18 AM: {SystemFailure} Failure in JanitorEvent while pruning cells.
6/3/2016 1:02:28 AM: {SystemFailure} Failure in JanitorEvent while pruning cells.

Oh. And:

1
2
3
4
5
6
7
6/3/2016 1:01:48 AM: {SystemWarning} Item.CopyItemFromDictionary(24550) ITEM ID does not exist.
6/3/2016 1:01:48 AM: {SystemWarning} Item.CopyItemFromDictionary(100) ITEM ID does not exist.
6/3/2016 1:01:48 AM: {SystemWarning} Item.CopyItemFromDictionary(8010) ITEM ID does not exist.
6/3/2016 1:01:48 AM: {SystemWarning} Item.CopyItemFromDictionary(15010) ITEM ID does not exist.
6/3/2016 1:01:48 AM: {SystemWarning} Item.CopyItemFromDictionary(25020) ITEM ID does not exist.
6/3/2016 1:01:48 AM: {SystemWarning} Item.CopyItemFromDictionary(7206) ITEM ID does not exist.
6/3/2016 1:01:58 AM: {SystemWarning} Item.CopyItemFromDictionary(33020) ITEM ID does not exist.

Definitely some more cleanup to do. Tomorrow.


[Day 47 code - tests (actually just SQL scripts)

Comments