Project's still going, but it feels like there's not much to show for it. Why? Because there's been a lot of back-end code being written, and a lot of db & comms testing. Still it's not been without a few little wins along the way. Most significant of which is that my xml/lua UI scripting works.
Arguably, this is where my 'agile' code-and-refactor approach is at its weakest. The UI scripting and how I manage lua objects in the UI will undoubtably require some revision, which will in turn require revision of a number of script files and xml UI layouts to accompany every code change. On the upside though, something works man, and that's cool.
Among other features is the MD5 hashing and salting of passwords during login. Currently, the actual game packets are unencrypted, but I'm not sure how much I care about that at the moment.
Of course, all of this feels like it's distracting away from writing the game and focusing on coding gameplay and generating content. So I'm very keen to get the backend stuff up and running soon.
Current status of the game project: motoring along, albeit slowly.
The screenshot below shows the visually underwhelming result of a few days work on the servers. Yet to me, it's a significant step forward.
Previously, the game's servers were all implemented as console applications - a watchdog, a gateway, another for authentication, another for chat (per server cluster), and a series of world servers for serving the world(s) in that cluster. The problem, of course, came in trying to debug the suckers, since they all can possibly interact with each other in some way or another, and getting one process to stop when I'm breaking into another was nigh on impossible. I guess if I'd thought through the design a bit more I'd have realised this early on, but you know, hindsight's 20/20 and all that...
To simplify things then, I modified the application class the console processes shared into something that I could integrate into a single windows application.
Now, I can: - start this ServerHost application up with a commandline parameter, to automatically load one or more selected servers. - use the arrow buttons to cycle through the console windows of each running server - load or terminate servers while it's running - load servers from a batch - enter commands on any server's console (or on the serverhost to query the main process) - break into the servers and have the debugger stop all running server threads.
Amusingly, I did all of this using what seems a by-now antique Win32 approach (message pump, WM_COMMAND, etc etc). I didn't want the overhead of MFC, I didn't want to mixed-mode into C# (I still wanted the servers in C++), and after all, given the servers are console apps, the user interface is 'just' a simple dialog, right?
Turns out I've forgotten more about Win32 programming than I care to admit. There was a time when it was all I was doing, all day, every day. But it's been... more than a decade? really? So just getting this little baby to this stage took more work than I expected.
The last week or two have been hectic, but productive. The program is now talking to the database; frameworks for the watchdog, authentication and chat servers are written and getting closer to testing, the scriptable UI is nearing completion. It sounds like progress - but of course the project is just a bunch of half-finished branches in mercurial at the moment waiting debugging and merging into my development trunk.
Part of this multifaceted approach stems from working in multiple places. If I'm working on my laptop during my lunchbreak, I'll be working on a feature that I don't need done right now - while what I'm working on at home in the evening will be something I want finished, and soon.
One of the other side projects has been fixing up my predictive state components. Taking some inspiration from hplus0603's EPIC, I made a little test program that allows me to view a simulated motion state on the client (blue), server(red) and a remote client (green). It's a much better approach than trying to solve it in the game's 3d view As can be seen, the current implementation is quite a bit off - there's a lot of room for improvement. So solving this - and updating the components in the game code - is one of this weekend's projects.
I have a friend who is a full-time author, publishing multiple novels a year. From the outside it would seem he has an inhuman ability to focus - to spend every waking hour at his profession, focusing on a single outcome, writing his novels in irrepressible fits of creativity. The reality is a little different. He'll spend a certain number of hours each day writing new material for next years book, some time researching the book he's thinking of writing the year after that, a couple of hours editing the book that he's planning on releasing later this year, an hour reading (again) the galleys for the book his publisher wants final approval on. After which he'll be updating social networking sites, blogs, accounts and other business tasks related to his job.
There are abundant similarities to the indie developer - and maybe a little hope, too. If we need a break from the coding, there's always art needing to be done, or music, or sound effects, or web design, or marketing. Maybe we're doing it ourselves (and does 'programmer art' really need to be a pejorative?), or maybe we're incorporating art and services created by a third party, but either way we're forced to switch tracks regularly.
I take a measure of reassurance from the author's approach. Like the author, we find ourselves switching mental tasks - we are analytical, then creative, then critical, then business, then social... To an outsider I suspect it looks like we're suffering a multiple personality disorder. But I beg to disagree - it's simply part of being a professional. And, I gotta admit, it's also a bit of fun.
Over the last week I've been refactoring my entire application in a number of areas, as well as adding a few new features:
It now uses a comprehensive component/entity system for all mob/player functionality
The component system is asymmetrical, allowing for server-side rule enforcement, client-side prediction, among other things.
Much of the terrain code has been abstracted into my static library so that client & server calculate the same results for visibility hulls etc.
A first attempt at client side prediction.
Entity (player & mob) interest areas. It all sounds like great progress, except that I've not started testing the changes. So who knows how long that's going to take? How long is a piece of string?
Despite a few times thinking that things were getting ludicrously complicated, I managed to keep my sanity: I broke up the coding sessions with a bit of tinkering in the LightWave Trial. Though trying to work out what tools I want in my artwork pipeline has probably cost me more lost sleep than any coding issues.
The kids have given me a few spare minutes this weekend (and I've taken a few more besides) to work on my client/server state data.
Previously, I had some rudimentary state information in there and was concentrating on getting the basics of the terrain communicating back and forth. Fine for terrain work, but not so fine when I want things to start moving. So now, I want to get my non-terrain objects moving correctly on the client and server.
Part of the fun in all this is that the system is somewhat asymmetrical - and this was doing my head in for a while. The server has the definitive set of entity data - whether it's position and velocity, or inventory or achievements. The server also keeps track of who has a registered interest in a particular entity - whether it's because they're near (for visible updates such as position or clothing), or because they're operating an inspector (comparing achievements, for example). The server also has to be robust - I don't want an out-of-bounds update from a client crashing it. Motion updates from clients are error-corrected over time to account for latency and clamped to some sane maxima.
The client, on the other hand, is working a little differently. Only updates for entities under the player's direct control get sent back to the server, there is no clamping during position/velocity error correction, and there's (currently) no need for the notification message queue used on the server.
Given that previously I had, well, nothing, implementing some sort of even rudimentary entity system that came close to these objectives took three or four tries. There's a lot of cleanup to do, so the jury's still out, but I'm hoping that what I've come up with will work. Eventually.
So I spent too many hours lately fixing bugs introduced when I rearranged a whole bunch of structure code and messed up the order of initialisation of a couple of objects. Sigh.
Progress on the client-server movement will take at least a couple of days, and there's plenty more to do besides. But hey, it is a nice antidote to writing accounting software during the daylight hours. And for my esteemed colleagues and fellow forum addicts, here's a couple of screenshots - the older wireframe mode and the newer textured mode. Lighting is just cheap GL light values for the time being, and the textures aren't really chosen for their artistic merit ;) Wireframe was handy early on when working on building a visibility list and overall rendering efficiency. There are around 117M cells in the dev terrain for the renderer to iterate through.
Up until now I've been rendering everything wireframe. And even then, I've been only rendering the 'top' faces of my terrain heightmap. Last night I decided to spend a bit of time on the cosmetics - in the hope that it'll make development a little more fun in future iterations. So there were four main things achieved:
add a skybox. It doesn't do much, but it's how I want rendering to fill in the blanks in future, so something needs to be there now, even if it's just flat-shaded-blue.
render the sides of the terrain. This turned out to be harder than I expected, as the terrain is not a simple rectilinear AABB problem, and there was a bug in one of my normal calculations that had me pulling my hair out for a good hour or two.
add some demo lighting. While not my intended final implementation, I've used a cheap OpenGL light to simulate the motion of the sun. Seeing the effect of this on the terrain was really rather cool!
add some texturing. A sample texture pasted on everything revealed some interesting artifacts leftover from the terrain generator. It was immensely satisfying to see what I'd previously only seen in wireframe rendered solid (and without the ugly normal glitch it started out with). Good stuff.
Tonight I will probably take a break from the coding for a little while and continue work on some artwork. In the meantime that gives me a bit of space in which to consider a few of the issues I have to overcome in the next few steps:
Client/Server movement prediction & sanity checking.
So I clicked Save instead of Publish on the last post... I'm such a noob sometimes.
Last development session felt very productive. I fixed a highly annoying networking bug - it finally irritated me so much I couldn't ignore it any longer. Turns out I'd missed setting an event somewhere and coincident timing issues would cause it to randomly drop out. Much better now!
Also, the collision detection algorithm finally worked correctly, after several prototypes and iterations. I felt like I'd been working on it forever, and my desk has been inundated in scraps of paper illustrating various aspects of it. Who knew colliding and physics with a spherical grid would get so complicated. Okay, don't answer that. So after I showed the results to the Mrs, I pulled up the file history in tortoiseHg and looked - nope, not forever. Only two days. But they were two long days!
I'm tired of looking at wireframes - I've started coding the solid/textured world, along with a mode switch allowing me to switch back to wireframe for various test purposes. So I guess that's next on the agenda. Along with a few dozen other things...
According to TortoiseHg my project is 5 weeks old. A fair amount has gone into it in that time, more than I can cover here. Instead, I intend to simply record what was achieved in my last development session(s) between journal posts. At least this way I, and you, can see that 'stuff is being done'.
In the true spirit of emergent design, last night's session was spent refactoring a chunk of functionality - player action and camera controls were brought over to the new action containers, and player physics was split out into its own handling functions. Collision detection was rewritten (again) because the game's non-linear 3D space makes efficient collision detection a little non-trivial.
And then I spent a good couple of hours banging my head on the keyboard trying to figure out why suddenly my player stopped moving. In the end:
Buggy rotation code. Rather than copy and paste, or (God forbid) actually moving the old rotation code into an abstracted rotation function, I'd retyped the rotations for the player camera orientations. Big problem, of course: I'd forgot a Conjugate() call on my quaternion code and *foom* everything stopped working correctly. Note to self: You wrote a simpler Rotation function already - use it and optimise later!
Very small numbers. Measuring the angle between two vectors is all cool and stuff, but translating back from the collision detection's linear result to the non-linear worldspace was causing near-zero rounding errors. Time to swap all that junk out for a proper slerp or - more likely - just use a linear interpolation at that point anyway. After all, we're talking about movement between frames here, it's not like the user's going to notice anything.
Ah well, some thinking on it today then more coding tonight - if I fix this maybe I can go resolve that horrible client connection bug.