Saturday, December 31, 2011

Farewell, 2011!

Here we are at the end of an amazing year. Team Laser Combat has come a long way, but not nearly as far as I'd hoped in the beginning. Thankfully, many of those delays were caused by very good things, such as:

  • The Global Game Jam.
  • The Game Developers Conference.
  • The birth of my son, Avery.
  • Teaching several new courses in an ever-changing curriculum.
  • My mad dash to finish my masters degree (almost there!)
  • Traveling to visit our families for holidays.
  • Our fourth wedding anniversary.
  • And many more good things.

Man, it's been a great year!

So Where Are We?

Well, with all of the events going on this week, I haven't had a whole lot of time to devote to fixing the defects mentioned in my last post.  In fact, I seem to have made them worse instead of better.  But that's OK -- I've made another radical decision that seems crazy but is almost certainly good for the end result.

Character movement is the most complex thing I've implemented so far.  I originally had it working well for local clients, but it was unreliable for network clients.  My solution was a compromise between something that worked well and looked "just OK".  Now that most clients are local clients, I'm going to return to my original algorithm but change the way the network messages are sent and handled. It'll look better and it should fix the character duplication bug that I mentioned in my last post.  (Besides, it'll allow me to prototype something that will be needed in my next collaboration, Botz.)

What's Next?

So the next steps, which will begin 2012 for me and TLC, are as follows.

  • Improve the character movement algorithm.
  • Fix the intermittent spectator bug.
  • Change the network message handlers to delegate to methods rather than handle the messages themselves. 
    • Also, change the local clients to call those methods directly.
  • Remove network handling of objects that no longer need to be sent across the net.


Onward to 2012!

This year was awesome and I'm very excited about what the coming year will bring, both personally and professionally. I hope all of you have good things coming as well!


Wednesday, December 21, 2011

Testing the New Client/Server Arrangement

After the brief delay caused by my hard drive failure, the code is now in place for the local versions of the client and server.  The first round of testing has produced a pretty intimidating to-do list. Here's what went down:

The Procedure

I established a testing procedure that I believed would involve a sample of the affected functionality and uncover any regression issues. This is not a comprehensive test plan, but it did involve a good representative sample of client/server interaction.
  1. Select Single Player from the main menu.
  2. Log in as myself (Michael).
  3. Select a team color.
  4. Recruit a team captain.
  5. Send a chat message from the Lobby.
  6. Recruit another character.
  7. Upgrade a character.
  8. Signal ready.
  9. Move all characters through two or three rounds in the game.
  10. Cycle through the team and character info displays.

The Results

I went through those same steps four times in a row without modifying the code. The test results follow.

Step Test 1 Test 2 Test 3 Test 4
1 Passed Passed Passed Passed
2 Passed Passed Passed Passed
3 Passed Passed Failed (Server registered me as a spectator.) Passed
4 Passed Passed Unable to proceed. Passed
5 Failed (Engine defect.) Failed (Engine defect.) Failed (Engine defect.)
6 Passed Failed (Character list had disappeared.) Passed
7 Passed Unable to proceed. Passed
8 Passed Passed
9 Passed Failed (My characters worked but one AI got duplicated.)
10 Passed Passed


Conclusion

There is more work to be done!  I'm going to tackle one defect at a time and stick with these same ten steps until they work reliably.  Then I'm going to elaborate with a more detailed test plan.

Monday, December 19, 2011

Hard Drive Failure!

I hit a little bit of a snag in the project yesterday:  My hard drive began throwing errors and had to be replaced.

My first thought was that it was going to be an all-day project.  The first time I had to replace a hard drive (about 16 years ago), it took an entire weekend and two big economy-sized boxes of floppy disks.

But today, through the miracle of modern technology, it took only a few hours!  And that includes backing up the old drive, installing the new one, and restoring the disk image to it.  Super easy and with no problems whatsoever!  I now have 50% more drive capacity, 50% better seek times, a much faster (and more reliable) boot process, and no error messages complaining about error reports and failed writes.

Yay!  Now back to Team Laser Combat.

Friday, December 16, 2011

A Possible Alternative for the Server Upgrade

I had a thought today that I just want to capture here so I don't forget it.  Rather than give the server the complete overhaul that I described in my last blog post, I think I can get by with a better, simpler, more maintainable option.

In the current system, MHServerModule uses MHClientInfo's output stream to send messages to the client. Here's my new idea:

  1. Move the send() method from MHServerModule into MHClientInfo.  
  2. Extend MHClientInfo into MHLocalClientInfo and override the send() method to talk straight to MHLocalClient.
  3. When a client connects to MHServerModule, the method of connection will determine which version of the client info object is instantiated for that client.  If it's a network connection, it will associate an MHClientInfo with that user. Otherwise, it will use MHLocalClientInfo instead.
  4. MHServerModule will continue to run the listener thread automatically so the same server can be used for local or networked play without modification or subclassing.

I can't wait to see if this idea is as great as I think it is. Of course I'll continue to post my progress here.

Thursday, December 15, 2011

Moving on to the Server Side

OK, the client is working well in its new, more loosely-coupled form.  The only client-side component left to test is the new local client, which can't be properly done until it has a local server to talk to. That means it's time to turn my attention to the server side.

The best habit I've picked up lately is that I always begin a refactoring effort by analyzing and documenting the existing system first.  Here's the server's current form:


And here is a rough idea of what I have in mind for the imminent refactoring:



Check back in a few days to see how it's going.  :)


Friday, December 9, 2011

Client Upgrade in Progress

The refactoring of the engine's client package is working well so far.  I have managed to split apart the code that handles networking from the general client code without affecting the existing functionality of Team Laser Combat.  Here's the new class diagram.


Remaining tasks before the client upgrade is complete:
  • Rename MHClientModule to the more appropriate name MHNetworkClient as shown in the class diagram.
  • Refactor the server package to add compatibility for MHLocalClient.
    • Build a prototype to test both the networked and local versions of the client and server.
  • Test the new version of MHGUIChatClient that now depends on MHObservableClient to send notifications of chat messages.
  • Add logic to TLC to launch the correct client/server connection based on user role.
  • Move the net package into the io package (mhframework.io.net).
    • Modify the deployment scripts to accommodate the new package hierarchy.





Monday, December 5, 2011

The New and Improved mhframework.net.client Package

Here's another class diagram of the mhframework.net.client package with several corrections and elaborations.


The heart of the new design is MHAbstractClient.  It will contain some useful constants along with basic implementations of common methods.

Derived from that is MHClientModule -- a class that already exists in an incohesive form. The new version will separate the low-level network communications into a new MHNetworkClient class, and will keep the stuff that's specific to a single client. There's no new functionality here; just a better division of labor.

Another subclass of MHAbstractClient is MHLocalClient.  I'm not sure if the engine itself will have this implementation, but I included it in the diagram anyway to demonstrate what I had in mind. The idea behind it is that situations where the game server is hosted on a player's machine should not require network communication, so a "dummy" class can take the calls and then just update the local data rather than send actual messages across the network...unless, of course, the update must be broadcast, but that can be handled on a case-by-case basis.

Finally, there's MHObservableClient.  This class will take an MHAbstractClient implementation as a parameter to its constructor.  This means that any subclass of MHAbstractClient can be made observable.  It maintains three different lists of listeners:

  • MHSystemMessageListener:  A listener for handling messages predefined by the engine.  These messages will be handled by the engine, but notifications can be sent to any class who subscribes to them.
  • MHChatMessageListener:  A listener specifically for chat messages.  May also be used to broadcast status messages from the server. The MHGUIChatClient component will implement this interface and provide a method for registering an MHObservableClient object
  • MHGameMessageListener:  A listener for handling game-specific messages.  These messages must be handled by the game code.
I haven't implemented this new design yet, but my goal is to have it in place and utilized by TLC by the end of the month.  Stay tuned to see if I can hit that target!

Tuesday, November 29, 2011

Redesigning the Engine's Network Client

Perhaps a good place to start the refactoring process would be in the engine itself.  How's this look for a redesign of the mhframework.net.client package?


Corrections to be made to this diagram:
  • Declare sendMessage() in MHAbstractClient superclass.
  • Remove sendToAll() -- that's a server function.
  • Consider making MHLocalClient observable.  Or make an observable subclass of it.
  • MHObservableClient needs separate lists of observers for system messages vs. game messages.

More to come...

Monday, November 21, 2011

Rethinking Single-Player Mode

As I mentioned in my last rant -- I mean, "blog post" -- the game needs to be refactored before I go any further.  So I'm starting with the change that will do the most good:  removing all networking code from the single-player game mode.

What's the Problem?

Since the game was primarily intended to be a multiplayer game, the single-player mode has been treated almost like an afterthought.  Basically, it's just the multiplayer game configured to have just one human player.  Seemed like a good idea at the time.  Unfortunately, this means that I'm not only troubleshooting data issues and gameplay logic, but I'm also at the mercy of the underlying network even when the only client is on the same machine as the server.

What's the Plan?

The plan, therefore, is to remove all networking functionality from the single player mode.  The question is "how?"  Well, I've got an idea.

The current chain of responsibility goes like this:

  • TLCScreenBase is the base class from which all game screens are derived.  When a screen needs to update data, it calls out to TLCDataFacade.
  • TLCDataFacade is the single point of contact for all data updates and retrievals for the entire system.  If the data to be updated must also be shared with the server or other players, the data facade hands it off to TLCGameClient.
  • TLCGameClient is the intermediary between the local game instance and the network.  It takes responsibility for sending, receiving, and processing application-specific network messages, the actual transmission of which is handled at a slightly lower level by the engine's MHClientModule class.

My plan is to have TLCGameClient implement a version of the strategy pattern so that, upon instantiation, it will either create a true network client (as it's doing now) or it will create a simple object that "fakes" the network communication.  So in single-player mode (and perhaps even multiplayer hosting mode), the data will simply be communicated to the game server via method calls rather than being sent out on the network.  The server will implement a similar mechanism for communicating to local clients.

With this new system, the instantiation rule for each user role might be like this:

  • Single-Player:  Local client
  • AI Player:  Local client
  • Host LAN:  Local client
  • Join LAN:  Network client
  • Spectator:  Network client

What Could Go Wrong?

  • TLCDataFacade.  It currently contains a very complex mechanism for tracking individual data for multiple users.  This will not be necessary once the refactoring is complete, and should itself be refactored once the single player mode is separated from the networking functionality.  It should probably no longer be a singleton.
  • TLCGameServer. Since the local clients won't be using network communication to talk to the server, then the server should not use it to talk back to the clients.  A protocol must be established for the server to know how it should be communicating with each client type.  (My first thought on this:  Keep a list of network connected clients only, and then broadcast to them whenever a change is made.  Local clients will simply share the data with the server.)




Sunday, November 20, 2011

Candidates for Refactoring

It's official; Team Laser Combat is in serious need of a refactoring.  Because some elements of the original technical design were carelessly lost during implementation, the project has reached the a point where adding even simple pieces is becoming unnecessarily difficult.

The highest priority refactorings, as I see them, are these:
  1. There is no reason whatsoever to have single player mode use network messages to communicate between the client and server.  The proxy pattern prescribed in the original tech design would solve a number of current frailties and intermittent failures, as well as improve performance..
  2. The network modules really need to operate on a publish/subscribe model.  The observer pattern would greatly simplify the message handling code (which is a huge chunk of the system), eliminate some recurring errors, improve the functionality of the user interface, and go a long way to clean up the overall architecture of the client.
  3. I may do away with the authoritative, standalone game server.  Not sure about this yet.  I fear that the added simplicity of the game client would come at the cost of testability.

So much to do, so little time!