My favorites | Sign in
Project Home Downloads Wiki Issues Source
Search
for
DevelopersGuide2  
For developers only.
Phase-Requirements, Phase-Design, Phase-Implementation, Featured
Updated Apr 15, 2010 by jdwxj...@gmail.com

Welcome to GameAnywhere.

GameAnywhere is a file synchronization software that enables gamers to bypass the hassle on reconfiguring game settings and easily have their saved game data with them anywhere, anytime.


Getting Started

In this section, we would introduce the basic features of GameAnywhere and what you will need to develop GameAnywhere.

Software Requirements

Features of GameAnywhere

  • Enables you to carry your personal game data in a thumb drive or have them stored in your free online account.
  • Easily syncs your game data between PC, thumb drive and your GameAnywhere online account.
  • Automatically detects the games installed on the computer and offers you the appropriate synchronization options.
  • Restores the computer to its original state after you are done playing on the computer with the files you have synchronized.
  • Allows users to add their own games.
  • Does not require installation.
  • Is free and open-source.

Screenshots


Software Architecture

In this section, we will give you a high level overview of the components in GameAnywhere.

This diagram depicts what happens in the program.

The Controller is declared and the Controller starts up the GUI. The GUI interacts with the user.

In a typical synchronization scenario, the user indicates the direction of the synchronization first. The GUI will request information regarding the games from Controller, which in turn calls GameLibrary for the information to return to GUI.

After the user selects the games to synchronize, GUI will then create a list of SyncAction with the games' information and send it to Controller for synchronization. Controller will then provide the information to the relevant sync class to process.


Software Data Structure

This section describes the various classes that were used to store information.

Game

Game is a class that stores the necessary information regarding a Game, i.e. game file path, install path, game name.

SyncError

SyncError stores the information for an synchronization error. It would contain the unsuccessful sync file/folder path, the process that encountered this error and lastly, the error message.

SyncAction

SyncAction contains the necessary information to sync a game. A Game object and a list of SyncError are wrapped in a SyncAction object. The unsuccessfully synced files will be related to the Game object. Initially, it contains an empty list of SyncError when it is created by the GUI.

SyncAction also contain the sync action, which indicates what type of game files to be synced. There are basically two types of games files, saved games files and game configuration files. User can choose to sync either one or both.


Class Summary

GameLibrary Class

The GameLibrary class, contains all the methods and information to initialize installed games into a list of games, that will contain all the appropriate paths to the config files and saved game files of each individual game.

It will also resolve and return the common set of games that are found in both the source and target paths according to the synchronization direction chosen by the user, through the method GetGameList(direction). The direction of synchronization must be properly defined with this method.

Sync Class

This parent class contains the general methods to backup and restore the computer to original game state.

OfflineSync Class

OfflineSync Class inherits from Sync Class. This class contains the algorithm to handle the synchronization between computer and thumb drive. The sync direction determine how the game files are transferred.

OnlineSync Class

Similar to OfflineSync Class, OnlineSync Class inherit from Sync Class. OnlineSync Class contains the algorithm to handle the synchronization between computer and a GameAnywhere Online Account.

WebAndThumb Class

This class handles contains the algorithm to handle the synchronization between thumb drive and a GameAnywhere Online Account.

WebComms

This class contains the methods and information needed to connect and communicate with the a GameAnywhere Online Account.


Game Files Storage Structure

In GameAnywhere, we are concerned with the two types of game files. They are Configuration files and Saved Game files.

Games files on the computer are detected automatically (see Games Detection).

This is how game files are stored on the external device:

A general structure looks like this:

  • GameAnywhere.exe
  • SyncFolder
    • Game 1
      • config
      • savedGame
    • Game 2
      • config
    • ...

Example:

Use camel case for sub-folder names i.e. "savedGame".

SyncFolder

GameAnywhere would create a folder to store all the games files that you would want to save. This folder is called SyncFolder. It would be located at the same directory as GameAnywhere.exe.

The subfolders in SyncFolder are the game folder(s). Each of the game folder is named after a game.

Configuration and Saved game files are stored in their respective folder under a game folder.


Adding Games

To edit the supported games in GameAnywhere, simply edit the userGames.txt file located in the same directory as GameAnywhere.exe.

Variables Needed to Add Game

Critical game information

Variable Name Description
Game The Game name.
RegValue The name of the registry entry, in the registry folder, that contains the install path.
RegKey Path to registry folder of game.
RegType KLM for HKEY_LOCAL_MACHINE or HKCU for HKEY_CURRENT_USER


Paths for files

Variable Name Description
ConfigParentPath Full path to the parent path of all the config game folders/files.
ConfigPathList Full paths to config files separated by comma.
SearchConfigparent Regex search to handle batch processing or variable folder/file names for config files.
SaveParentPath Full path to the parent path of all the saved game folders/files.
SavePathList Full paths to saved game files separated by comma.
SearchSaveParent Regex search to handle batch processing or variable folder/file names for saved games.


Reserved Words/Variables that can be used in the paths for files

Reserved Words/Variables Description
InstallPathVar Can be used to replace the InstallPath recorded in the registry.
DocumentsPath Can be used to replace the document paths of running machine, etc: “C:\Users\Tom\Documents\”
RegistrySoftwarePath Can be used to replace the registry software path for the different types of OS. For example: “RegistrySoftwarePath\EA Sports\FIFA 10” (with HKLM) will evaluate to “HKEY_LOCAL_MACHINE\SOFTWARE\EA Sports\FIFA 10” for non-64bit OS users and“HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\EA Sports\FIFA 10” for 64bit OS users.

Syntax Rules

  • All critical game information variable must be present.
  • If config files exist, ConfigParentPath must be present, likewise for saved game files/SaveParentPath.
  • [ENDGAME] after the end of each game (see example below).
  • Comma can be used to separate entries for ConfigPathList, SearchConfigParent, SavePathList and SearchSaveParent.
  • To write a comment line, begin the line with #. Example:
  • #This is a line of comments.
  • There can only be one entry each for ConfigParentPath and SaveParentPath.
  • SearchConfigParent/SearchSaveParent are for regex searching to handle variable folder or file names. Example:
  • SearchSaveParent = A.*, B.*
    Possible Result: "A.boa", "B.ho", "B.man"
    * is a wildcard that will match any character(s). 
    It will search in the SaveParentPath for all possible files. 
    Then these will be added into the saved game list. 
    An alternative way albeit slower is to add the full paths of these files into SavePathList separated by comma.

userGames.txt Example

Game=FIFA 10
RegValue=Install Dir
RegKey=RegistrySoftwarePath\EA Sports\FIFA 10
RegType=HKLM
ConfigPathList=DocumentsPath\FIFA 10\user
ConfigParentPath=DocumentsPath\FIFA 10
SaveParentPath=DocumentsPath\FIFA 10
SearchSaveParent=A. *,B. *,C. *,D. *,I. *,J. *
[ENDGAME]

Game=Dragon Age Origins
RegValue=Path
RegKey=RegistrySoftwarePath\BioWare\Dragon Age
RegType=HKLM
ConfigPathList=DocumentsPath\BioWare\Dragon Age\Settings
ConfigParentPath=DocumentsPath\BioWare\Dragon Age
SavePathList=DocumentsPath\BioWare\Dragon Age\Characters
SaveParentPath=DocumentsPath\BioWare\Dragon Age
[ENDGAME]

Game=Batman Arkham Asylum
RegValue=Install Directory
RegKey=RegistrySoftwarePath\RocksteadyLtd\Batman Arkham Asylum
RegType=HKLM
ConfigPathList=DocumentsPath\Eidos\Batman Arkham Asylum\BmGame\Config\UserInput.ini,DocumentsPath\Eidos\Batman Arkham Asylum\BmGame\Config\UserGame.ini
ConfigParentPath=DocumentsPath\Eidos\Batman Arkham Asylum\BmGame\Config
SavePathList=DocumentsPath\Eidos\Batman Arkham Asylum\SaveData
SaveParentPath=DocumentsPath\Eidos\Batman Arkham Asylum
[ENDGAME]

Offline Synchronization

Offline synchronization includes synchronizing between the computer and the SyncFolder. SyncFolder is located on an thumb drive.

Synchronizing Thumb Drive to Computer

Steps for synchronizing from Thumb Drive to Computer:

  1. Create a backup folder in the game file parent directory.
    • If backup folder exists, skip backup process.
  2. Move original game files in the computer into the backup folder to complete backup process.
    • If backup is not successful, skip sync for game.
  3. Copy the game files in the thumb drive into the computer.

Synchronizing Computer to Thumb Drive

Steps for synchronizing from Computer to Thumb Drive:

  1. Remove existing game files in thumb drive.
  2. Create the necessary game folder structure in the external storage device.
  3. Copy game files from computer into the new directory.

Restore Computer to Original Game State

Steps for restore:

  1. Remove game files on computer.
  2. Move game files from backup folder into it's original directory.
  3. Remove backup folder.


Online Synchronization

Synchronizing Computer to GameAnywhere Online Account

This is a one way synchronization from PC to GameAnywhere Online account. Here is how it works:

  1. Given the game and type of data(saved and/or config) to sync.
  2. If the game is available on user’s web account, delete the respective saved and/or config folder of the game.
  3. Given a list of saved/config data files to backup, we will upload them one by one.
  4. In the event there is an error with the upload, it will accumulate the errors and return a list of sync errors.
  5. Lastly, add the list of sync errors to a list of unsuccessful synced files.

Synchronizing GameAnywhere Online Account to Computer

Steps for synchronizing from GameAnywhere Online Account to Computer:

  1. Create a backup folder in the game file parent directory.
    • If backup folder exists, skip backup process.
  2. Move original game files in the computer into the backup folder to complete backup process.
    • If backup is not successful, skip sync for game.
  3. Copy the game files in the GameAnywhere Online Account into the computer.


Thumb Drive and Web Synchronization

Web and Thumb Drive Synchronization is a two-way file-level synchronization operation. The aim of this operation is to ensure that the game files stored on the web are the same as the game files stored on the thumb drive. The files on both sides will be checked and compared against a metadata file that is stored on the thumb drive and the user would then be asked to resolve any outstanding conflicts that cannot be automatically be resolved.

Metadata file

The MetaData object stores the the path of the files as well as the checksum of each file in the SyncFolder. We have used a Dictionary of strings to store them. This MetaData object is then output as a serialized metadata file. There will only be one metadata file being stored in the thumb drive (metadata.ga). This file would only be created if a user selects Thumb drive and Web sync.

Here is the format of how the contents of the metadata is stored:

Path MD5 Hash codes
/config/wc.dat 4F33DSFE4234
/config/controls/key.bin 54DS65GHDH6
/saved/stage2.dat 43FSDFS3SFD4

  • The MetaData object contains a Dictionary<String, String> FileTable which stores the paths of the files as keys, and their MD5 Hash codes as the corresponding values.
  • The keys are not specific to local or remote paths, only including the path starting from the game name (i.e. “Warcraft III/config/CustomKeys.txt”).
  • The metadata file stores the state of the files that are previously successfully synchronized between the Web and Thumb Drive.
  • The metadata file is created/updated only when Thumb Drive and Web Synchronization is executed and not the other modes of synchronization. (See Web and Thumb Drive Synchronization Algorithm)

Synchronization Algorithm / Conflict Resolution

Since the metadata file stores the state of the previous successful synchronization, it can be used to compare if the files have been change, deleted or newly created.

Metadata and Syncing

When The WebAndThumbSync object is instantiated, it will:

  • Create the MetaData object by de-serializing the metadata file (localMeta).
  • Create a MetaData object of the current state of the files in the Thumb Drive (localHash).
  • Create a MetaData object of the current state of the files on the Web (webHash).

Checking Conflicts

The CheckConflicts() method is called to check for conflicts, which either can automatically be resolved, or requires the user resolution. Conflicts are checked by comparing the three MetaData objects created, iterating through each entry of the FileTable data member.

Scenario: No Conflict

Automatic Conflict Resolution

Y = Yes, N = No
File exists in localHash File exists in localMeta File exists in webHash localHash vs.localMeta webHash vs.localMeta Result Action
Y Y Y Hashes are the same. Hashes are the same. No changes since last sync. None
Y Y Y Hashes are the same. Hashes are different. File on web has changed. Download
Y Y Y Hashes are different. Hashes are the same. File on thumb drive has changed. Upload
Y Y N Hashes are the same. - File on web has been deleted. DeleteLocal
N Y Y - Hashes are the same. File on thumb has been deleted DeleteWeb
Y N N - - File on thumb drive is newly created. Upload
N N Y - - File on web is newly created. Download
N Y N - - File on both thumb and web has been deleted. DeleteMetadata


Scenario: Conflict(s)

Manual Conflict Resolution by User

Y = Yes, N = No
File exists in localHash File exists in localMeta File exists in webHash localHash vs.localMeta webHash vs.localMeta Result Conflict Resolve Option
Y Y Y Hashes are different. Hashes are different. Both thumb drive and web has changed. Upload Or Download
Y Y N Hashes are different. - File on thumb drive has changed and file on web has been deleted. Upload Or Delete local files
N Y Y - Hashes are different. File on web has changed and file on thumb drive has been deleted. Download Or Delete Web File
Y N Y - - File on both thumb drive and web are newly created UploadOrDownload


Conflicts and GUI

  • All conflicts that are automatically resolved are stored in static Dictionary<string, NoConflictDirection> noConflict with their respective actions.
  • All conflicts that cannot be automatically resolved are stored in a static Dictionary<string, ConflictDirection> Conflicts with their respective conflicts.
  • The Conflicts Dictionary is then passed through FilterConflicts() which “folds” the conflicts from file-level to folder-level (Config or savedGame) for each game.

  • The user is not allowed to resolve conflicts on a file-level basis, as it would be more intuitive for them to select the direction of conflicting Config or savedGame files.
  • The folded Dictionary is then passed back to the GUI as a Dictionary<String, int> where the int values are initialized to 0.
  • The GUI gets his input from the user, changes the 0 to either a 1 or 2 depending on the user’s choice and calls OnlineSync.SynchronizeGames(Dictionary<String, int> resolvedConflicts) with the updated Dictionary.
  • The resolvedConflicts Dictionary then passes through MergeConflicts() which will “unfolds” the conflicts to file-level according to the Conflicts Dictionary and add the resolved conflicts to the noConflict Dictionary.
  • The whole noConflict Dictionary is then processed entry-by-entry and the files will be synchronized.

GameAnywhere Online Account

Overview

To provide users with their own GameAnywhere web account, we need a database to store user account information and Amazon Web Services(AWS) SimpleDB was chosen. Furthermore, by allowing users to synchronize their game data to the web, we need to provide them with a web storage. Thus we would be using AWS Simple Storage Service (S3). For more information about the benefits using AWS, please visit http://aws.amazon.com/.

Here we will share with you how authentication is done for a user to login.

Authentication

How the Components Interact

User

The User component consists of user related functions such as Login, Register, ChangePassword, Logout, etc. It is an abstraction of what a user can do. Behind each function, it actually interacts with the database on the cloud(AWS SimpleDB) to retrieve, create and update information. As such, we have a specialized component called SimpleDB, which we will discuss further.

SimpleDB

In AWS SimpleDB, a table is called a domain while rows are identified as items, and columns are attributes. The primary key to distinguish a unique row is known as the item name. So here is an overview of the SimpleDB component, it is meant for communicating with AWS SimpleDB and it provides database functions like:

  • Inserting an item into Amazon SimpleDB, use the InsertItem method.
  • Getting an item’s attribute value, use the GetAttribute method.
  • Updating an item’s attribute value, use the UpdateAttributeValue method.
  • Checking if an item exists in the domain, use the ItemExists method.
  • Adding a new attribute to an item, use the AddAttributeValue method.

This component is dependent on the AmazonSimpleDBClient, which is part of the .NET AWS SDK provided by Amazon.

AmazonSimpleDBClient

The AmazonSimpleDBClient component is a wrapper class. It mainly deals with amazon SimpleDB web service directly by sending requests and receiving responses from it. By using the AWS SDK for .NET, it hides all the low level amazon webservices programming like authentication and error handling which are actually SOAP/REST calls. You may download the latest Amazon Web Services SDK for .NET from http://aws.amazon.com/sdkfornet/.

Database Structure

The domain we have created and will be using is called “UserAccounts”.

Each item/row in the database has the following attributes: ItemName, Password, ActivationStatus, ActivationKey. The ItemName acts like a primary key, there should be no duplicates in the domain. And every attribute value is of string datatype as it is a limitation of AWS SimpleDB. Below shows the structure of the “UserAccounts” domain:

Password Security

In order to ensure optimum security of users password, all passwords are encrypted in our database. This is secure because even us admins do not know your password as it is not even readable from the database.

MD5 is a one way encryption that we have used. It will always return the same hash value for the same given input. The way we store your passwords is to MD5 hash your username together with your password. This is a method known as Salted MD5, it ensures that no two users will have the same MD5 hashed passwords even if they have similar passwords. For more information about MD5, please visit http://msdn.microsoft.com/en-us/library/system.security.cryptography.md5.aspx.

You can find the CreateMD5Hash method being used very frequently in the User component for processes such as the Login and Registration.

Registration

To register for an account we need the following details:

  • Username (which will be a valid email)
  • Password (with at least 6 characters)

Before adding a user into the database, it first ensures that the user account does not exist in our database. Here are the steps for inserting a user to the database:

if (!UserExists(email))
{
  //Registration complete
  string activationKey = CreateMD5Hash(email.Substring(email.Length / 2) + password);
  string md5Password = CreateMD5Hash(email + password);

  //Insert user info into DB
  db.InsertItem(email, md5Password, activationKey);
  SendActivationEmail(email, password, activationKey))
}
  1. Create an activation key by getting the MD5 hash of user’s partial username and password.
  2. Create the encrypted password by getting the MD5 hash of the username and password.
  3. Insert the user account details into the database, this includes the activation key, username, and encrypted password.
  4. Finally, send out an email to the user with an account activation link together with the username and password. The activation link is of the following format, http://game-anywhere.com/activate/?key=activation-key.

In order to reduce the number of spam users, all accounts registered with us would require to be activatd by clicking on the link provided in our email after registration. Lets take a look at how it is done:

  1. Initially when a user is added to the database, an attribute “ActivationStatus” is set to value ‘0’ by default.
  2. When the user clicks on the activation link in the email (http://game-anywhere.com/activate/?key=activation-key), the website actually matches this activation key with the activation key found in the database.
  3. If the activation keys match, it will update the “ActivationStatus” to value “1”. There can be only 1 matched item because the activation key is a Salted MD5 string.

Login

Login requires a username and password from the user. Here are the steps to login a user:

if (UserExists(email) && IsAccountActivated(email))
{
  string userPassword = db.GetAttribute(email, "Password");
  string md5Password = CreateMD5Hash(email + password);
  if (userPassword.Equals(md5Password))
  {
    this.email = email;
    this.password = password;
    this.state = UserState.UserLoggedIn;
    return true;
  }
}
  1. With the username, check the database if the user account exists and is activated.
  2. If user exists and account has been activated, retrieve the user’s encrypted password from the database.
  3. Create a encrypted password using the CreateMD5Hash method with the user’s input(username and password).
  4. Compare the encrypted password from the database and the one created from the CreateMD5Hash method.
  5. The passwords should match and the user is logged in.

Password Retrieval

The password retrieval system does not actually send a user back his original password but rather it sends the user an email to reset his password. The reason is because the passwords in the database are encrypted, thus we are unable to recover a user’s password using the username. Here is how the resetting of password works:

if (UserExists(email))
{
  if (IsAccountActivated(email))
  {
    //Retrieve complete
    string password = db.GetAttribute(email, "Password");
    string resetKey = CreateMD5Hash(email + password);

    //Insert new attribute to item DB
    db.AddAttributeValue(email, "ResetKey", resetKey);
    SendPasswordEmail(email, resetKey))
  }
}
  1. Check if user exists and is activated in the database.
  2. If user exists and is activated, retrieve the encrypted password from the database.
  3. Create a reset key using the CreateMD5 method with the username and encrypted password.
  4. Add a new attribute called “ResetKey” to the user’s item in the database with the reset key we just created.
  5. Send out an email with a reset password link. The link is of the following format, http://game-anywhere.com/reset/?key=reset-key.

When the user receives the Reset password email, he may choose to ignore it. However, in order for the user to reset his password, here is how it is done:

  1. The user’s item in the database now has an attribute called “ResetKey”.
  2. When the user clicks on the reset password link in the email(http://game-anywhere.com/reset/?key=reset-key), the website matches this reset key with the one in the database.
  3. If the reset keys matched, a random password is generated.
  4. With the username and random password, an encrypted password is created using MD5.
  5. The attribute “ResetKey” is deleted from the user’s item.
  6. Update the user’s password in the database with the new encrypted password.
  7. An email is sent to the user with the new password.

Change Password

To change a user’s password, it requires the user to provide the username, current password and new password. Here is how the password can be changed:

if (UserExists(email) && IsAccountActivated(email))
{
  string userPassword = db.GetAttribute(email, "Password");
  string md5OldPassword = CreateMD5Hash(email + oldPassword);

  //Check if current password matches in DB
  if (userPassword.Equals(md5OldPassword))
  {
    //Change to new password and update item in DB
    string md5NewPassword = CreateMD5Hash(email + newPassword);
    db.UpdateAttributeValue(email, "Password", md5NewPassword);
  }
}
  1. Check if user exists and is activated in the database.
  2. If user exists and is activated, retrieve the user’s encrypted password from the database.
  3. With the current password, create the encrypted password using the CreateMD5Hash method with the username and current password.
  4. Match it with the one retrieved from the database.
  5. If it matches, it means that the user entered the correct password successfully.
  6. With the new password, encrypt it using the username and new password.
  7. Update the user’s item in database with the new encrypted password.

Resend Activation Email

At times, users might have our activation email in their spam folders or GameAnywhere fails to deliver the email. Thus, a ResendActivation method which takes in the username and password is needed. In order to reduce spams, we disallow malicious users to enter usernames of unactivated accounts by enforcing a password to be entered as well. Below is how ResendActivation method works:

if (UserExists(email))
{
  if (!IsAccountActivated(email))
  {
    string password = db.GetAttribute(email, "Password");
    string md5InputPassword = CreateMD5Hash(email + inputPassword);
    string activationKey = CreateMD5Hash(email.Substring(email.Length / 2) + inputPassword);

    if (md5InputPassword.Equals(password))
      SendActivationEmail(email, inputPassword, activationKey))
   }
}
  1. Check if user exists and account is not activated in database.
  2. If user exists and account is not activated, retrieve the user’s encrypted password from the database.
  3. Create the activation key by getting the MD5 hash of the partial username and password.
  4. Since the password from the database is encrypted, we need to encrypt the username and original password first in order to check if they matched.
  5. If they match, send an email to the user with the activation link.

API Reference

Click here for GameAnywhere API.


Sign in to add a comment
Powered by Google Project Hosting