Author Topic: Autopatcher: Special cases  (Read 2626 times)

Oliver Smith

  • Full Member
  • ***
  • Posts: 173
  • Karma: 7
  • Oliver Smith
    • View Profile
    • Oliver's blog
Autopatcher: Special cases
« on: May 01, 2006, 06:23:12 PM »
Firstly: Kudos on the autopatcher, it's a great anchor point for getting into Raknet.

I wonder if you could look at adding a Special Case mechanism, though.

Case 1: The patcher binary has changed.

If your patcher is called "patcher.exe" it cannot download an update to itself. Typically people download it to a temporary file, and then use a "shuffle" to swap the new executable in. And typically if there is a new patch.exe you may want to download the new .exe down on its own and then restart to use the latest patcher code for downloading/patching.

This would be awesome functionality to build into the Autopatcher itself but isn't essential.


Case 2: A control manifest

My patcher supports a file called "patch.xfiles"; this consists of a list of file names to be removed or renamed. If the player connects and patch.xfiles is in their download list, I want them to download patch.xfiles, apply any deletes/renames, and then re-run the patch list generation process.


I envisage something like:

Code: [Select]
std::string g_newPatcher = "" ;

struct PatcherSelfInList
{
  void operator () (DownloadingFile& files, const char* filename)
  {
    // Called when the patcher finds "patch.exe" in the filename list
    files.clear() ;
    files.SetDownload(filename) ;
    g_newPatcher = filename ;
  }
} ;

struct PatcherSelfDownloaded
{
  void operator () (const char* filename)
  {
    // Called when patcher.exe has downloaded
    MessageBox(T("Patcher Updated"), T("A new version of the patcher has been downloaded, the patch process will now restart"), MB_OK) ;
    rename("patcher.exe", "patcher.old") ;
    rename(filename, "patcher.exe") ;
    SystemExecute(filename) ;
    exit(0) ;
  }
} ;

struct PatcherXfilesInList
{
  void operator ()(DownloadingFile& files, const char* filename)
  {
    // Called when the patcher finds "patch.xfiles" in the filename list
    // (unless we also had patcher.exe)
    files.clear() ;
    files.SetDownload(filename) ;
  }
} ;

struct PatcherXfilesDownloaded
{
  void operator () (const char* filename)
  {
    FILE* fp = fopen(filename) ;
    while ( !feof(fp) )
    {
      char oldfile[MAX_PATH+1], newfile[MAX_PATH+1] ;
      if ( fscanf(fp, "-%s\n", oldfile) == 1 )
        unlink(oldfile) ;
      else if ( fscanf(fp, ">%s>%s\n", oldfile, newfile) == 1 )
        rename(oldfile, newfile) ;
      else
      {
        cerr << "Invalid patch xfiles file" << endl ;
        break ;
      }
   }
}
     

...

  autoPatcher.RegisterFilenameWatch("patcher.exe", PatcherSelfInList()) ;
  autoPatcher.RegisterFilenameWatch("patch.xfiles", PatcherXfilesInList()) ;
  autoPatcher.RegisterFileDownloadWatch("patcher.exe", PatcherSelfDownloaded()) ;
  autoPatcher.RegisterFileDownloadWatch("patch.xfiles", PatcherXfilesDownloaded()) ;

OvermindDL1

  • Anti-Spam Moderator
  • Hero Member
  • ****
  • Posts: 855
  • Karma: 40
  • Programmer
    • View Profile
    • OvermindDL1's Site
Re: Autopatcher: Special cases
« Reply #1 on: May 01, 2006, 06:45:37 PM »
On point 1:  You cannot alter a file that is currently locked by the OS, however, what I have done in the past is generally just have the exe be a launcher, it contains the real patcher as a resource and extracts it to %temp% and runs that passing in the location it needs to work on.  That allows the patcher file to be modified during the upgrade, even if it needs to upgrade itself before all other files, it just recalls the first file, kills itself, and it repeats, getting the normal updates then.

Point 2 has already been discussed around here, and would be nice, but the general consensus is that the autopatcher is up for updates by anyone who wants to update it, but rak'kar would prefer to put his time into the real networking.  So, if you wish, update it and submit a patch. :)