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!


Saturday, September 17, 2011

Don't Get All GUI On Me

It's been pointed out that the client-side class diagram that I posted last night doesn't include anything for the user interface.  I have two things to say about that.

First, it was intentional. If you look at the project plan that I posted about a month ago, you see that "Token Source" and "Token Inventory" come before "Draw Token Action" and "Token Display GUI".  The Token Source is handled by the server, and the Token Inventory resides on the client.  The next two steps require user interaction, but the back-end support needs to be there first.

Second, it's not entirely true.  The diagram shows that TLCToken inherits from MHActor, which promotes and simplifies the rendering of animated graphics in the engine.  Also, the diagram mentions methods like sortByAttackValue() and sortByDefenseValue(), which will provide sorted lists to be displayed and selected from in the Attack command and the Defend interface.  The properties of the token stacks are also values that will appear on the token inventory display.  So there's a lot of stuff that will support the UI, even if it's not explicitly represented in this diagram.

Satisfied?  Is everybody happy now?  :)

Friday, September 16, 2011

The Client's View of the Token System

As promised earlier, here is a fairly high-level view of the client side of the token system.  You may notice some classes in common with the server side.  Code reuse is just good software engineering, of course.  :)


The Server's View of the Token System

The process of implementing the token system has begun!  The core gameplay revolves around random chance factors combined with how the player uses the resources that his/her team has available.  These resources come in the form of tokens -- combat tokens, heal tokens, power tokens, and grenade tokens.

Here's the class diagram of the system's server-side components.  I will follow up later with the client side.



Sunday, September 11, 2011

Lessons Learned, Part 1

It's never too early to start a project's postmortem, and I've had a lot of thoughts floating around in my head of things I really want to remember for my next project.  I think I can keep these thoughts from becoming regrets if I record them and learn from them, so here's my first list of lessons learned in this project.

This is not to say that the project is over, of course.  It's far from it.  I just don't want to lose these valuable lessons in the meantime.
  • First and most importantly, make all games data-driven from the start, even if they're only single-player.
    • Along these lines, all objects in the game should have ID values of some sort that allow easier serialization, database storage, and network communication.
  • Don't use networking code for single-player mode. Use the remote proxy pattern.  My original technical design specified this, but that detail was somehow lost once implementation began.
    • This type of information loss is a crime! I must not let it happen again.
  • Dynamic and finely-placed objects should not be part of game map structure.  The engine's map rendering algorithm uses coarse object placement as a matter of necessity, which makes it impossible for an object to lie randomly on the ground, or for a character to walk smoothly from one map cell to another.
  • Network modules that receive messages should use the observer pattern.  This will enable different UI components to respond immediately to high-priority messages coming in without waiting for the rest of the messages to dequeue, and allow messages of different types to be sorted upon arrival.  (System messages versus chat messages versus character movement commands, etc.)
  • Model-View-Controller principles are always relevant.  ALWAYS! Even beyond the basics of the Single Responsibility Principle.  Perhaps the high-level architecture should always begin this way and then evolve to fit the individual needs of each project. This may be worth further consideration.
  • An unrelated discovery: sliding doors can be animated in real time by generating the image and cropping it. This is a profoundly good idea.
  • Audio spatialization is crucial, especially when the entire game world doesn't fit on one screen. This shortcoming of the engine must be implemented before development of Beltzhian Marauders can begin.
There are sure to be more to come.  I know this doesn't cover them all!


Saturday, August 20, 2011

Progress Report (08/20/2011)


The slim chance of finishing my degree earlier than anticipated has raised the priority of reaching the alpha stage on this project, so I've been forcing it into any free moment I can find lately!


Accomplishments:
  • The players take turns correctly now.  That bug is dead and gone.
  • Investigated the bug with the actions menu, but the problem still remains.  Something is keeping the human players' characters from performing two actions back-to-back unless the actions menu is artificially refreshed.  
    • I put over three hours into troubleshooting this problem and still haven't found a solution.  Fortunately, as I mentioned in my previous post, there is an easy workaround by either trying again or refreshing the menu.
  • Discovered a bug that's only possible when you have multiple characters on your team.  As long as you leave one of your characters stationary, then your other characters can move an unlimited number of times until you move your stationary character and use up his action points.  Should be an easy fix, but I haven't tackled that one yet.
  • Gave the design doc an overhaul to update it with the recent requirement changes and fill in some of the "to do" items.  The new game design document is version 2.3.
Known Issues:
  • Something is keeping the human players' characters from performing two actions back-to-back unless the actions menu is artificially refreshed.  
  • The game gets stuck in the lobby if the host is a spectator rather than a player.
  • As long as you leave one of your characters stationary, then your other characters can move an unlimited number of times until you move your stationary character and use up his action points.
  • Sometimes network errors will cause an AI to be disconnected immediately after it connects.
  • Network latency causes character upgrades to not show up right away.  The client needs to wait for the updated character to return from the server before returning to the team screen.
  • The lobby in multiplayer mode doesn't turn control over to the player until the host has signaled ready.
  • Chat messages get lost when a user in multiplayer mode switches between the lobby and the team/character configuration screens.
  • When a player drops off, their team data is orphaned.  The server needs to recognize this and place the orphaned team under AI control.

Next Steps:
High Priority:
  • Fix the action menu bugs mentioned above.
  • Create the token factory.
  • Create the token inventory system.
  • Create the token display GUI.
  • Implement the Draw Token action.
Medium Priority:
  • Sometimes network errors will cause an AI to be disconnected immediately after it connects.  This causes the lobby screen to wait indefinitely for a player who will never arrive.  The server should detect this and try again to create the AI player.
    • Solution: Refactor the engine's networking modules to use the Observer Pattern. This will also correct the "Known Issue" mentioned above with abandoned team data.
  • Investigate ways to dynamically color the team uniforms.  Experiment on the placeholders.
    • If this works, add the ability to dynamically color MHFont objects too.
  • Create the in-game chat component.
    • But first, fix the issue with the lost messages by making the data structure static.
  • Create the HUD's event log display.
  • Finish the level design guide.
  • Finish asset lists for current set of level designs.
Low Priority:
  • Implement the Heal action.
  • Implement the Attack action.
  • Finish the "whose turn" display.
  • Finish voice scripts for narration.
  • Finish the team creation screen.
    • Put in the floor image for the captains to stand on.
    • Replace plain gray buttons with captain character images.
  • Let's see if we can allow the player to change video modes dynamically from the options screen so they don't have to close the program and rerun it to change resolutions.
  • Make the AI players taunt each other in the lobby chat, just for fun.
  • Design the web site.
  • Get coin display graphics from the art team.
    • Add it to the team configuration screen.the character configuration screen and the recruitment screen.
  • Replace the temporary column header graphic on the character equip screen.

Thursday, August 18, 2011

Taking turns -- it works!

Yes!  My AI players are now taking turns correctly.  They're finally playing nice with one another like good little boys and girls.  My proposed hypothesis was correct -- the necessary code wasn't being invoked by the proper message handlers.

On that note, I'm goin' to bed.  I'll tackle the Move command bug tomorrow.

Thank you and goodnight!

Tuesday, August 16, 2011

About those two bugs I mentioned...


In my previous post, I mentioned that there were two known issues remaining in the turn-based functionality.  In the interest of honesty, disclosure, and bug tracking, I thought it might be a good idea if I actually record what those issues are.  So here ya go.

First and most importantly, the server fails to advance to the next player once a player has finished his/her turn.  There is no workaround, but I do have an idea about what's causing it: the location of the functionality.  I think I put it in the message handler for the CHARACTER_MOVE message, but I don't think that message is actually being used.

Second, the Actions menu has a bug where you can only move a character one time.  If you try to move again, the character ignores your command.  There is an easy workaround for the time being:  If you click the Test button on the HUD, it resets the menu and your character can move again.  The solution to this problem is most likely in the initialization of the menu, which would explain why resetting the menu fixes the problem.

Monday, August 15, 2011

Looking to the Horizon

I'm getting pretty close to fixing all the bugs with character movement and taking turns (there are just two known issues remaining), so it seems like a good time to lift my head, look around, get the lay of the land, and see where I'm headed next.  Here's the plan for the near future as I see it right now.



Sunday, August 7, 2011

The "Whose Turn" Bug -- Solved!

The problem apparently had something to do with static vs. non-static variables.  When I made the "whose turn" value static, the problem went away, implying that perhaps the current player's data was not being updated when it should have been.


This has led me to the next bug:  Action points are not being deducted when characters move.  Ah, a fresh new challenge!  Yay!


Thursday, August 4, 2011

The "Whose Turn" Bug -- Update 2

The proposition I made in my last post was indeed correct -- the AI players are not receiving the notification that the program has transitioned from the lobby state to the game state.  The question of "why" still remains.

Just wait.  I'll figure this out.  Eventually.

Monday, August 1, 2011

The "Whose Turn" Bug -- Update

My last test showed that the method in question isn't even getting called.  This means that I must turn my attention to a higher level and find out what could be prohibiting this condition from being evaluated.  The most likely candidate is that the AI players are not being notified that the server has transitioned into game state and the game has begun.

More to come after I get another chance to look at the code.  Who knows when that will be?

Friday, July 29, 2011

The "Whose Turn" Bug

The AI players are still refusing to acknowledge their turns.  I haven't yet had a contiguous block of time to do an in-depth debugging session on it, but I have verified a few minor elements of the process.  This is just a note to keep track of what has been attempted and what is to come next.


Hypothesis #1:  The AI characters weren't moving because they had no action points assigned.
Procedure:   Manual trace of source code to identify logic that may be prohibiting the movement functionality.
Test Results:  Action points are not yet being validated by the server, so this is irrelevant.


Hypothesis #2:  The AI characters aren't receiving the notification that it's their turn.
Procedure:  Console output from both client and server whenever the "whose turn" message is sent or received.
Test Results:  All clients, including the AI, are receiving correct values from the server regarding whose turn it is.


Hypothesis #3:  The method for determining whether a player is a human or an AI is faulty.
Procedure:  Trace the isAIPlayer() method to validate its functionality.
Test Results:  I have not had time to do this yet.  It is the very next thing I will attempt.



At the moment, there are no further hypotheses regarding this defect.  I'm always open to suggestions if anyone has any ideas that I haven't thought of yet.

More to come on this issue.

Saturday, July 16, 2011

Progress Report (07/16/2011)

Again, my job has kept me from doing much with the project, but I have been paying some attention to it in the few moments that time has allowed.  Really, there's just one thing that has been drawing my attention:  the refusal of the AI characters to move when it's their turn.

Based on the accomplishments listed in the last report, the priorities of some tasks have been rearranged.


Accomplishments:
  • Nothing quite...but efforts are underway to get the AI players to acknowledge their turns.
Known Issues:
  • Network latency causes character upgrades to not show up right away.  The client needs to wait for the updated character to return from the server before returning to the team screen.
  • The lobby in multiplayer mode doesn't turn control over to the player until the host has signaled ready.
  • Chat messages get lost when a user in multiplayer mode switches between the lobby and the team/character configuration screens.
  • When a player drops off, their team data is orphaned.  The server needs to recognize this and place the orphaned team under AI control.

Next Steps:
High Priority:
  • Make the AI characters move when it's their turn.
  • Formalize the flowchart for the AI logic.
  • Create the token factory and displays.
  • Implement the Draw Token action.
Medium Priority:
  • Sometimes network errors will cause an AI to be disconnected immediately after it connects.  This causes the lobby screen to wait indefinitely for a player who will never arrive.  The server should detect this and try again to create the AI player.
    • Solution: Refactor the engine's networking modules to use the Observer Pattern. This will also correct the "Known Issue" mentioned above with abandoned team data.
  • Investigate ways to dynamically color the team uniforms.  Experiment on the placeholders.
    • If this works, add the ability to dynamically color MHFont objects too.
  • Create the in-game chat component.
    • But first, fix the issue with the lost messages by making the data structure static.
  • Create the HUD's event log display.
  • Finish the level design guide.
  • Finish asset lists for current set of level designs.
Low Priority:
  • Implement the Heal action.
  • Implement the Attack action.
  • Finish the "whose turn" display.
  • Finish voice scripts for narration.
  • Finish the team creation screen.
    • Put in the floor image for the captains to stand on.
    • Replace plain gray buttons with captain character images.
  • Let's see if we can allow the player to change video modes dynamically from the options screen so they don't have to close the program and rerun it to change resolutions.
  • Make the AI players taunt each other in the lobby chat, just for fun.
  • Design the web site.
  • Get coin display graphics from the art team.
    • Add it to the team configuration screen.the character configuration screen and the recruitment screen.
  • Replace the temporary column header graphic on the character equip screen.