Yearly Archives: 2007

JetBrains ReSharper

I just finished a trial of JetBrains ReSharper 3.0, an add-on for Visual Studio 2005 designed for code analysis and refactoring.

ReSharper’s main feature is automatic code analysis. When you open a code file, it will scan for and higlight errors in your code and show an error count and error locations on the sidebar. It also goes a step further than the compiler by highlighting warnings and making suggestions for improving code.

For many errors, it will pop up a lightbulb icon if it knows how to fix the problem. If you click this icon, it will give you a menu that will let you perform a quick-fix.

ReSharper is smart enough to warn about places where a NullReferenceException could occur and overrides intellisense with its own, more thorough version. It gives more parameter information, shows more class info, and takes intellisense to the next level in general.

Visual Studio’s refactoring options are a neat addition, but not overwhelmingly useful. ReSharper extends them quite a bit to add a lot more functionality. I never really made much use of ReSharper’s refactorings since I prefer to change things by hand.

ReSharper has quite a few features that I couldn’t imagine ever using, such as code generation, code templates, and build script editing.

Although it add a lot of features and functionality to Visual Studio, in a project of any significant size (such as the 116k-line Basternae codebase) it causes a drastic slowdown, rendering my development machine nearly unusable at times, especially when code analysis is grinding away on a large code file. It’s true that the codebase I’m working on isn’t optimal (huge classes, bloated files, plenty of errors, etc), but that’s why I’m working on it in the first place — to fix all of that.

It’s an ambitious tool, but perhaps it’s trying to do too much. Maybe future versions will be faster, but right now it doesn’t add enough value to the development process to justify the $149 price tag.

If JetBrains removed everything but the code analysis functions for a “lite” version that sold for $49 I’d buy it in a heartbeat, but as it is now ReSharper doesn’t speed up my development process more than it slows it down. I’ll look at the 4.0 version when it comes out, but 3.0 isn’t for me.

A Simple Solution

This may only be a temporary solution until I find a better way, but for now we just number skills and spells in the constructor based on a reference count (static int _numSpells), essentially like this:

Spell()
{
SpellNumber = _numSpells;
++_numSpells;
}

This insures that nobody will get a duplicate and is a simple way to do things. More importantly it was quick to implement and didn’t break anything.

We’re now down to 16,156 errors.

Just A Little

Small change in numbers: We’re now at 17,270 errors.

One of the problems I have to solve is to find a clean way to create global references to specific spells and skills without them actually being globals (which are ugly and disgusting and a horrible thing to put in code).

For example, in C, we used something like skill_bash which was just an integer referring to the skill number for bash. At runtime, when all the skills were initialized, the value of skill_bash would be set. It didn’t really matter what order skills were created in, because skill_bash would always point to the bash skill, whether it be number 35 or 350. The problem with this method is that is uses a global variable. It’s something that can be done in C#, but what, really, is the point of having a value containing the bash skill if you someday decide to take the bash skill out of the game. Then you have a bunch of useless code lying around doing nothing.

Not that bash will be removed from the game — this is something more likely to be an issue with spells.

I’ll have to look into reflection, delegates, etc. to see if there is some sort of common-sense way to handle this. I also have to keep in mind that someday I may want to convert the skill and spell tables to files that load at runtime and can be tweaked and adjusted without recompiling the entire codebase.

Since skills are so heavily involved in the game engine, it will be nearly impossible to decouple them completely.

A Productive Day

The error count is now down below 20,000. Quite a bit, in fact. We’re now at 17,719. This puts us at about 4500 for the day.

A large portion of the vanquished errors were just array initialization fixes — converting from C-style to C#-style, which is quite different. I can’t give a definite date, but I suspect this phase of the conversion/rewrite will finish in mid-August.

Overriding the NOT (!) Operator

One thing commonly seen in C and C++ code is use of the NOT operator to check whether a struct or class pointer is set to NULL. For instance:

class value = NULL;
if( !value )
{
printf( “value is null” );
}

In C# code this results in an error because the compiler has no idea what “NOT” means on a class.  To be able to use this syntax in C# you have to override the ! operator, which is something I’ve never had occasion to do, AND that there are no easy-to-find code examples of. Luckily it’s just like overloading any operator in C#:

public static bool operator !( ClassType ct )
{
if( ct == null )
return true;
return false;
}

It works and it saves me the trouble of changing around 700 lines of code. We’re now down to 20,392 errors.

Visual Studio Becomes More Responsive

I mentioned in an earlier post that Visual Studio 2005 was gradually becoming more responsive as the error count decreased.

On my system, which is a Pentium D 2.66 GHz with 1GB of RAM, it starts becoming usable again at about 22,000 errors (we’re at 22,267 now).  That’s where the “type-a-character-and-wait” transitions into using the application in realtime.

One thing to keep in mind is that I have a trial installation of ReSharper (which I’ll post about once I’ve had more chance to evaluate), which slows things down considerably due to constant recompiling to find errors in realtime and excessive intellisense-ing above and beyond that which Visual Studio does.  Without Resharper I think I would have noticed responsiveness a bit earlier, but for now I have to say that 22,000 errors should be considered the upper limit of usability in a system like mine.

With more RAM it would probably be a bit better, and at this point it probably makes sense to upgrade to 2GB (RAM’s gone down quite a bit recently, probably due to Vista finally starting to sell).  I’ll have to add that to my grocery list.

No Real Progress

Soooo… here’s my list of excuses:

1. I started a new job Monday (writing home automation software used to control lights, stereos, alarm systems, etc.)

2. I got married over the weekend.

3. I’m just plain tired right now.

So, not much progress in the past few days. The bug count is sitting at 22,677 right now. At that rate it would take about 396 days to finish. It won’t take that long.

A Little Progress

We’re down to 22,906 errors now. The errors are getting a little harder to smash, but we’re crushing them into tiny little bits nonetheless.

VS2005 Regular Expression Search Rules!

One of the things I had to do to eliminate a few thousand bugs as part of this C++ to C# conversion is replace the text transmission functions.

Nevermind how they work internally, the important thing for the sake of the current conversion is that they look completely different.

The old functions looked something like:

send_to_char( “Words.\n\r”, ch );

While the new functions are supposed to look like:

ch.SendText( “Words.” );

With around 4000 or so calls to that function, it would be a dauntingly huge project to retype every reference to send_to_char. Because it’s a bit more complicated than a simple word replace, we would be hosed if not for Visual Studio 2005’s regular expression search and replace.

If you Google regular expression search-and-replace, most likely you’ll come up with a lot of people complaining about it. Ignore them — those people are whiny idiots. It is easily one of the most useful things ever added to Visual Studio and it takes about 10-15 minutes to get the hang of.

To make the above change, all I had to do was do a search for:

send_to_char[(] {:q}, {:i} [)];

And replace it with:

\2.SendText( \1 );

As a basic explanation:

1. Anything in [] brackets means “any of these characters”. I had to bracket the parenthesis to keep the parser from evaluating them as an expression.
2. Anything in {} brackets means that it’s assigned an “expression tag”. It’s the equivalent of the scripting language act of assigning it to %0, %1, etc and they’re numbered in the order they are found.
3. :q means match a “quoted expression”.
4. :i means match a C++/C# identifier (i.e. a variable name).
5. \1 means “insert the first tagged expression”. \2 inserts the second, etc.

This is enough to get the basic idea going, and it works like a charm, provided the functions are spaced EXACTLY as indicated. If you have something like (notice spaces):

send_to_char(“Something” , ch );

It will not work. In any codebase that has had more than one person’s fingers in it, you’ll have inconsistent spacing. Some people will put spaces before/after every variable, some won’t, and some will be mixed. That’s why we have to set it to ignore spaces anywhere they will be a concern. We do this by inserting [ ]* which means “match anywhere from 0 to infinity spaces”. The search expression now looks like:

send_to_char[(][ ]*{:q},[ ]*{:i}[ ]*[)];

And now that I’ve figured out how to use regular expressions, all of the references to the Diku send_to_char function have been replaced with our shiny new code.

The error count is now down to 24,414.

Skwish Skwish Skwish Go The Bugs

Now we’re down to 30,975. Nothing interesting is happening, but we’re making progress.

Most of these errors are related to one of four things:

1) References to functions moved into classes have to be changed.
2) Pointer-based functions and comparisons that need to be rewritten to be reference-based.
3) Public vs. private data.
4) Different handling of arrays in C#.

The majority are #2, with a large quantity of each of the others. When you have 30,000+ bugs to fix, everyone gets their share.

Just Past Halfway

The compiler tells me:

“You have just passed the halfway point in the journey toward your next codebase.”

Errors are now quite a bit less thant the halfway mark (which would be 37,571).

We now have 35, 542 errors to resolve. We’re making pretty good progress so far.

Under 40,000

We’re down to 39,610 errors now. Even though that’s a stunningly huge amount, it’s still progress.

My brain’s starting to hurt, I should probably work on a different project for a few days.

Significant Progress

We’re down to 44,773 errors. That’s 12,486 fixed for today.

Visual Studio 2005 has become noticeably more responsive. It’s still a little slow and clunky, but each error corrected is a slight speed increase.

New Personal Error Correction Record

Yesterday I mentioned that I had 75,142 second-pass compile errors in the codebase. That’s a lot no matter how you describe it.

Aside from spending a couple hours reading Heinlein’s Revolt in 2100, all I’ve really done today is hammer away at the code trying to reduce that number. This has been a little slow because Visual Studio 2005 slows down A LOT when it has to store tens of thousands of error messages in memory and check every change you make to code against those errors to see whether it can remove them from the error list.

I really like intellisense and realtime error checking, but not when it pretty much causes the IDE to grind to a halt. As the number of errors decreases, VS is gradually becoming more responsive, but it’s still too much of a mess to be a very pleasant editing experience.

So, the number of errors is now 58,264. That’s still a ton, but I’ve now set a new personal record of fixing 16,878 compile errors in a single day. My previous record was about 8500, basically due to some weird recursive STL/templating issues with a C++ app I was writing a year or two ago.

Even better, the day’s still not completely over yet, so I could probably add a few more to that total.

I Broke The Compiler

Seriously.

I cleared up all the first-pass compiler errors (the remaining 1,447). It was tedious, but not too terrible. That means that the compiler made it to the second pass.

It churned away for a while, and then gave me a “build failed message”, which I expected. It then proceeded to show me every last little error that it could find.

There were seventy five thousand one hundred and forty-two errors.

After displaying that many errors, Visual Studio 2005 promptly crashed in a horrible flaming fireball of death.

There are only 116,000 lines of code in the whole codebase. That means two-thirds of the code is broken. Nice, eh? I wonder how long it will take me to fix 75k errors…

1,447 Errors

That’s a good thing. Down from 7,899 errors. Everything that could be fixed via search-and-replace (about 5,000 errors) has been, and the rest (about 1,400) have been edited by hand. There’s still a lot more work to do in stage 2, but the number of compile errors is steadily decreasing. Soon we will have a C# version.

C#: Stage 1 of 5 Complete

Stage 1 is done.

Q: What is stage one?

A: Hammering the code into C# syntax so that Visual Studio gives no complaint before trying to compile to code.

Q: What’s that involve?

A: Placing all of the functions into classes, eliminating all global variables, converting #define statements into variables (in the case of constants) or class methods (in the case of macros), changing all char[x] variable declarations to strings, rephrasing all array declaration and initialization, and removing stray const keywords.

Q: How many changes did you have to make?

A: I had to change about 4,000 lines of code, mostly by hand. I love search-and-replace, but it couldn’t do much here.

Q: Did you completely break the heck out of anything in the process.

A: ABSOLUTELY! I know for a fact that I will have to completely rewrite mob tracking (which has always been one of the things I intended to do anyhow). Some of the changes to correct syntax also just pushed the errors later in the process — they won’t show up in a syntax check and will instead show up in a compile.

Q: What are the other 4 stages of this conversion?

2 = Compiling without errors. This is a huge step. After just running the first initial build, there were 7,899 compile errors. A large percentage of these will be pointer errors because I didn’t change any pointer-based code (“Pointers and fixed size buffers may only be used in an unsafe context.”)

3 = Building an executable. This may be moderately complex, but since C# pushes so much of the work onto the syntax checker and compiler, chances are that if it compiles without errors then the program will build and run.

4 = Booting without immediate crashes. This will involve firing up the debugger and making sure that all of the changes didn’t have any unintended consequences. They will, errors are unavoidable in a rewrite of this magnitude. Hopefully debugging will be fairly quick.

5 = Logging a character in and walking around without crashes. Most of the code lies dormant until a player is logged in. This includes things like network code, combat routines, hit/mana/move regen, informational screens, skills, etc.

Completing all of this will get us ready to put up an alpha port of the game so that we can actively start building content.

The Idea Evolution of Basternae: Technical

Over the past few days I’ve spent a while working on rewriting the Basternae source code in C# (even though the original code is not completely object-oriented yet).  Ideally I’d like to have it run as a standalone application linked to a SQL server for data storage.  This is doable in C++, but in C# it’s far easier.

I still have the C++ version, but after some experimentation it looks like I’m going to stick with the idea of migrating to C#.  It’s been my favorite language lately, and it offers a bit more power than C++ does.  What better way to fully master a language than port a 115k-line project to it?  I will still have the old code to fall back on, but I hope to have the new code working in less than a month (which is the timeframe I had planned for the original string conversion anyway).

For now I’m pretty sure that I’m going to stick to C++ for the client, especially since it’s already written and just needs some slight modifications to work with the new engine and to work with Linux (ideally it will be able to run on Linux, Windows, and MacOS, but I have no access to MacOS so that’s a “maybe eventually” thing) .

As a techie I usually focus on the tech stuff first, but sometime soonish I’ll probably be posting about the gameplay changes I have in mind.