And I do realize that QuakeC is compiled, although I thought it was
compiled to a cross-platform byte-code that was then interpreted.
It is. It has it’s own virtual machine code, which gets compiled by qcc, and is then interpreted by the server C code. Works out nicely, since it traps runaway loops, null references, etc., like Java can do easily, but C++ can only do somewhat hackishly. The only downside is that it traps too easily on nested function calls, reporting as an infinite loop if you go over 32 recursive function calls, or so, which simply means you have to avoid recursion over long lists. With the server code available though, this constant is easily tweaked.
The fact that Carmack through together his own virtual machine, you know, just because, has always been an inspiration to me. =) It also means you have mods that can easily run cross-platform, without forcing the coder to compile to different target platforms. Since most servers run on linux, this presents issues to the .dll crowd that don’t know how to make .so’s.
QuakeC lacks a few things to be as general purpose as C. First, you
only have one ‘struct’ to work with, the Entity, IIRC. This leads to
massive overloading/reuse/abuse of every member variable, because
adding any new members increases the memory footprint of every
single instance.
Sure. By about 4k of memory footprint per member variable added, to the server (only). TF massively reused member variables, but, IMO, on today’s systems with 1GB or more of memory, 4k of memory is a trivial amount to add, especially when it makes your code look better.
There have several times been proposed overhauls by people to redo all of TF in C++ (you can see them on the forums I linked to, above), but the general consensus is there’s no real need for object oriented code. The existing codebase, IMO, works much better without OO than it would with.
Plus, dlls are windows-specific, so it would mean losing the ability to generate one compiled progs file and distribute it to linux, mac and windows servers, unless you wrote a C+±to-progs compiler, which seems a needless amount of effort.
Second, strings elements are not individually addressable, so string manipulation is nigh-impossible.
This was fixed back in, hmm, '98 or '99 or so. There’s real string manipulation now, along with arrays, which were also missing – but curiously not needed. 100k LOC, and I haven’t found the need for one array yet; the iterators provided by the server builtin functions allows one to iterate across basically any sort of entities in the game, whether it be sorted by space, or all clients, or all things with a classname of “rocket” or whatever.
It’s an interesting example of Turing completeness.
I did write a mod that allowed users to type commands to the server
console or other players consoles. It involved rebinding each key to
an impulse, building strings as a linked list of entities with one
string literal each, and then dumping them in order to the
appropriate console when ‘enter’ was pressed. Not so fun.
Yeah, this sort of hack isn’t needed any more.
In general, I actually think the underlying architecture of Quake1/Quakeworld is pretty superior. Not only does the virtual code / interpreter breakdown have great security benefits while still exposing quite a lot of power to modders, but the network code is, IMO, superior to any other FPS ever made. I stopped playing TFC because I couldn’t handle how slow and laggy TFC games were to QW. People in modern FPSs move slow. Mainly, because their network protocols suck, and so they disguise it by making people move slowly. It’s amazing to a modern player who goes back to Quake to see how fast all the targets are moving around. If you play HL deathmatch, and then Quake1 deathmatch, you’ll see what I mean. CustomTF has maintained it’s popularity over the years in part due to the love people have of the speed and flexibility of movement in the game.
The only real weakness of the Quake1 architecture is that all the client side prediction is hard-wired, and so there’s certain fundamental limits on what you can do, if you want to maintain compatibility with all Quakeworld clients. For example, there’s only 10 or so particle effects in the game, and you can’t add new ones without breaking backwards compatibility. Likewise, the prediction works great for FPS games, but reveals its weakness when you try to do Quake BattleChess, or whatever, like some mods did.
All in all, I think the story of the Quake engine is a very interesting one, and one that could use an article of it’s own. While the Quake wiki page goes into a little detail on the tech behind it, it’s not really very complete. The Quake family of engines, though, has grown dramatically over the years, as this image shows:
http://en.wikipedia.org/wiki/Image:Familytree11.png