Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

SimplePatchTool - open source patching solution for standalone platforms

Discussion in 'Assets and Asset Store' started by yasirkula, Jul 26, 2018.

  1. DrunkenImp

    DrunkenImp

    Joined:
    Jan 25, 2018
    Posts:
    51
    Hey, I keep getting an error: no suitable patch method found....?
     
  2. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,865
    Call UseRepairPatch(true).UseIncrementalPatch(true) methods of your SimplePatchTool object to instruct it to use these patch methods, when available.
     
  3. DrunkenImp

    DrunkenImp

    Joined:
    Jan 25, 2018
    Posts:
    51
    I figured out the issue, but how would I make it so if it doesn't find the game.exe it just downloads the entire thing.
     
  4. DrunkenImp

    DrunkenImp

    Joined:
    Jan 25, 2018
    Posts:
    51
    After making a repair patch, I get corrupted file on download.
     
  5. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,865
    Repair patch does that; if it doesn't find a file or if a file seems corrupt, it just downloads the entire file.

    If you are hosting your files on Drive, make sure that the directory holding your files is public (i.e. right click->Get shareable link). Otherwise, you may encounter the corrupted file error.
     
  6. DrunkenImp

    DrunkenImp

    Joined:
    Jan 25, 2018
    Posts:
    51
    So I just tested using the link generator for drive which works perfect, but I host my files on an amazon s3, and was trying to use BaseDownloadURL. Is there something I need to place in the Version info file besides just <BaseDownloadURL>amazonlink</BaseDownloadURL>…

    Edit, I had an extra whitespace in there...that's what I get for using notepad to input the url
     
    Last edited: Dec 5, 2018
  7. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,865
    If Amazon S3 links are like "amazonlink/RepairPatch/Game.exe.lzdat", "amazonlink/RepairPatch/Game_Data/globalgamemanagers.lzdat" and so on, then yes, simply setting
    <BaseDownloadURL>amazonlink/</BaseDownloadURL>
    should be enough (assuming that those files are public).

    Be aware that if Google Drive links still exist in your VersionInfo, setting BaseDownloadURL will have no effect because per-file download links have priority over BaseDownloadURL. In that case, you'll need to create a fresh new version (to quickly get rid of those Google Drive links) and then set its BaseDownloadURL.
     
  8. NyanHeavy

    NyanHeavy

    Joined:
    Dec 14, 2017
    Posts:
    8
    I thought it was something with my project, so I started a blank project and imported the asset. during the intros unity requests to fix some obsolete scripts, I tested correcting, and then without correcting, and the error persists.
     

    Attached Files:

  9. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,865
    @NyanHeavyCeo If you build your project to e.g. C:/MyGame directory, then put that path to the "Root path" field and put an empty directory's path to the "Output path" field. While importing the asset to your project, let Unity update the obsolete API automatically: "I Made a Backup. Go Ahead!"
     
  10. NyanHeavy

    NyanHeavy

    Joined:
    Dec 14, 2017
    Posts:
    8
    @yasirkula root path would be the path where my project would be when compiled?
     
  11. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,865
    Exactly :) I thought it was clear in the instructions provided on the GitHub repo.
     
  12. NyanHeavy

    NyanHeavy

    Joined:
    Dec 14, 2017
    Posts:
    8
    Maybe I did not interpret this part well, something told me that it was the cumin of the project, I will test and I will return
     
    yasirkula likes this.
  13. NyanHeavy

    NyanHeavy

    Joined:
    Dec 14, 2017
    Posts:
    8
    After a while I realized how idiotic my thought was, "how are you going to patch something that is not yet compiled"

    Thanks for the attention, now another doubt, you have an example structure of how it would look on the server
     
  14. tatelax

    tatelax

    Joined:
    Feb 4, 2010
    Posts:
    1,168
    I'm trying to follow the tutorial on Github but it's a bit confusing. I want to use the included Launcher Demo. As I understand it, I will need to maintain two patches: The Launcher & The Game.

    I created patches for both and uploaded to my web server. I put the URL's for each into its respective field in the inspector on the Launcher Demo component. However, it says in console "version info is invalid!"

    Also, after reading the tutorial I'm still unsure how the security tab of the patcher window is intended to work or what its purpose is. I'm also confused on what the Update tab is supposed to do.

    Any insight is greatly appreciated!

    Thank you.
     
  15. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,865
    @NyanHeavyCeo It's just the output of SimplePatchTool uploaded to a server:

    Code (CSharp):
    1. Server/
    2.    PatchOutputFolder/  <-- this directory and its contents must be public (accessible from outside)
    3.       RepairPatch/
    4.       IncrementalPatch/  <-- will not be present for the first patch
    @tatelax You are right that you have to maintain two patches. For each patch, you first have to upload a dummy VersionInfo to the server because you'll need its download url in your application: https://github.com/yasirkula/SimplePatchTool/wiki/Generating-versionInfoURL. After you enter these URLs to LauncherUI, you can proceed with building your projects, generating patches and uploading the files to the server: https://github.com/yasirkula/SimplePatchTool/wiki/Creating-Patches#after-creating-a-new-patch

    The Update tab is mentioned here: https://github.com/yasirkula/SimplePatchTool/wiki/Providing-Custom-Download-Links#b-automated-method. It is useful if you can't use BaseDownloadURL with the server of your choice.

    The Security tab is mentioned here: https://github.com/yasirkula/SimplePatchTool/wiki/Signing-&-Verifying-Patches. For this to work, you have to generate an RSA key pair, enter the public RSA key's contents to the LauncherUI's corresponding fields and then build your project. After generating a patch and updating the download links in the VersionInfo, you should sign VersionInfo.info and/or the PatchInfo files (e.g. 1_0__1_1.info) with the private RSA key. Then, you should upload these signed XML files to the server.
     
    hopeful likes this.
  16. NyanHeavy

    NyanHeavy

    Joined:
    Dec 14, 2017
    Posts:
    8
    Can the VersionInfo.info file be anywhere on the server? and where the game files should stay to be downloaded for the next update?
     
  17. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,865
    Yes, you can put your VersionInfo.info anywhere on the server, as long as it remains public. But you shouldn't move it after passing its url to the "Version Info URL" in your app.

    By game files, if you mean Unity's build directory, then you can keep these files on your local drive to be able to create an incremental patch in the next patch; if you mean the patch files generated by SimplePatchTool, then you can put them anywhere on the server, as well, as long as they remain public.

    What really matters is the VersionInfo.info. You must ensure two things:

    1- Your app has the correct Version Info URL to fetch the VersionInfo.info from
    2- The download links in your VersionInfo.info are valid
     
  18. DrunkenImp

    DrunkenImp

    Joined:
    Jan 25, 2018
    Posts:
    51
    Any info on self updating the launcher on Linux?
     
  19. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,865
  20. sliptrixx

    sliptrixx

    Joined:
    Mar 24, 2016
    Posts:
    12
    Hey. I tried uploading my first initial patch to an online server and a few files, around 20 .lzdat files, weren't uploaded due to it being unreadable. I tried both aws, and Google drive and both gave problems. Any idea why this might happen?
     
  21. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,865
    Really weird. Are there any "familiar" Unity files in these unreadable files, like globalgamemanagers.lzdat, level0.resS.lzdat or resources.assets.lzdat? Can you move any of these files to the desktop? Can you upload them to the server after moving them to the desktop?
     
  22. sliptrixx

    sliptrixx

    Joined:
    Mar 24, 2016
    Posts:
    12
    screen shot error spt.jpg

    So this is just the first few files. And the error count this time was about 87 files out of 198. Moving the files to desktop didn't help much. I have no idea what the issue is because the number of files failing to upload fluctuates constantly. One time it is as low as 20 and other times close to 160. I dont know whether familiar files were a part of the unreadable files. The last iteration it wasn't.
     
    Last edited: Dec 11, 2018
  23. DrunkenImp

    DrunkenImp

    Joined:
    Jan 25, 2018
    Posts:
    51
    I compiled the console version of the self patcher, and it works fine other than the fact it does not relaunch the launcher. Any suggestions?
     
  24. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,865
    @hibnuhishath Does using another browser or clearing the cache/cookies resolve the issue? I have uploaded multiple patches to Drive so far and never encountered this issue myself, so I'm unsure about the cause of this issue.

    @PolyCurseGames Did you rename the launcher's executable in this update? If not, then that's unexpected. I'm unsure whether or not it is a Linux-only issue but so far, the self patcher has been successfully relaunching the launcher on my Windows 10. You may also try disabling your antivirus software while patching the app just to see if it resolves the issue.
     
  25. sliptrixx

    sliptrixx

    Joined:
    Mar 24, 2016
    Posts:
    12
    Thanks a lot. Changing the browser never occurred to me. Microsoft edge had issue processing the file, while chrome worked flawlessly.
     
  26. NyanHeavy

    NyanHeavy

    Joined:
    Dec 14, 2017
    Posts:
    8
    Just to confirm, I have a folder on my server: GamePatch/Game that stands for my game.
    In GamePatch are the files like VersionInfo.info etc,

    The link that I should update in VersionInfo.info would be the direct link to the "Game" folder
     
  27. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,865
    If RepairPatch directory is a subdirectory of GamePatch/Game, and if your server is suitable for BaseDownloadURL, then yes, you can simply put the url of GamePatch/Game/ to BaseDownloadURL.
     
  28. sliptrixx

    sliptrixx

    Joined:
    Mar 24, 2016
    Posts:
    12
    After reading instructions on github, I still dont understand how to upload incremental patches. For example I have two patches, 1.0 to 1.1, and 1.1 to 1.2. So how should I upload them so a user in 1.0 can switch to 1.2?
     
  29. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,865
    Here, for 1.0 to 1.1, you should follow the "If this is your first patch" part and for 1.1 to 1.2, you should follow the "Otherwise" part.
     
  30. sliptrixx

    sliptrixx

    Joined:
    Mar 24, 2016
    Posts:
    12
    I did exactly as told by the documentation, yet patching doesn't seem to work. Can you check is there something wrong with my methodology and code.
    • There is a code attached to a game object in the main screen that reads from the VersionInfo.info file from the online server
    • The code initializes the patcher and checks whether a new update is available or not. If result is a success it runs the patcher, else it takes you to the login screen,
    • Once the update is complete, the restart the game message is shown.
    My issues and questions:
    1. patcher.FetchProgress() always returns null. Why?
    2. This isn't a working through a launcher and Im not using selfpatcher. Is this a mistake?
    3. Any other reason why its not working?
    My code:
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using SimplePatchToolCore;
    5. using SimplePatchToolUnity;
    6. using SimplePatchToolSecurity;
    7. using System.IO;
    8. using TMPro;
    9.  
    10. public class PatchToolScript : MonoBehaviour {
    11.  
    12.     void Awake()
    13.     {
    14.         InitializePatcher(Path.GetDirectoryName(PatchUtils.GetCurrentExecutablePath()), VersionInfoURL);
    15.      
    16.     }
    17.  
    18.     [Header ("Patcher Parameters") ]
    19.     [SerializeField]
    20.     private string VersionInfoURL;
    21.  
    22.     [Header("XML Verifier Keys (Optional)")]
    23.     [SerializeField]
    24.     [TextArea]
    25.     [Tooltip("Public RSA key that will be used to verify downloaded VersionInfo'es")]
    26.     private string versionInfoRSA;
    27.  
    28.     [SerializeField]
    29.     [TextArea]
    30.     [Tooltip("Public RSA key that will be used to verify downloaded PatchInfo'es")]
    31.     private string patchInfoRSA;
    32.  
    33.     [Header("UI Elements")]
    34.     [SerializeField]
    35.     private TMP_Text InfoText;
    36.  
    37.     [SerializeField]
    38.     private TMP_Text PercentageText;
    39.  
    40.     [SerializeField]
    41.     private TMP_Text ProgressText;
    42.  
    43.     [SerializeField]
    44.     private GameObject PatchUIElements;
    45.  
    46.     [SerializeField]
    47.     private GameObject LoginUIElements;
    48.  
    49.     private SimplePatchTool patcher;
    50.  
    51.     /// <summary>
    52.     /// Initializes the patcher
    53.     /// </summary>
    54.     /// <param name="rootPath"> The path of the executable path </param>
    55.     /// <param name="versionInfoURL"> Url of the versioninfo.info</param>
    56.     private void InitializePatcher(string rootPath, string versionInfoURL)
    57.     {
    58.         patcher = SPTUtils.CreatePatcher(rootPath, versionInfoURL).UseRepairPatch(true).UseIncrementalPatch(true).LogProgress(true);
    59.  
    60.         if (!string.IsNullOrEmpty(versionInfoRSA))
    61.             patcher.UseVersionInfoVerifier((ref string xml) => XMLSigner.VerifyXMLContents(xml, versionInfoRSA));
    62.  
    63.         if (!string.IsNullOrEmpty(patchInfoRSA))
    64.             patcher.UsePatchInfoVerifier((ref string xml) => XMLSigner.VerifyXMLContents(xml, patchInfoRSA));
    65.  
    66.         CheckForUpdates();
    67.     }
    68.  
    69.     /// <summary>
    70.     /// Checks for new updates and modifies UI appropriately
    71.     /// </summary>
    72.     private void CheckForUpdates()
    73.     {
    74.         if (patcher.CheckForUpdates(false))
    75.         {
    76.             ProgressText.text = patcher.FetchLog();
    77.             StartCoroutine(WaitingForCheckToComplete());
    78.         }
    79.     }
    80.  
    81.     /// <summary>
    82.     /// Enumerator that continues to check for updates
    83.     /// </summary>
    84.     /// <returns></returns>
    85.     private IEnumerator WaitingForCheckToComplete()
    86.     {
    87.         while(patcher.IsRunning)
    88.             yield return null;
    89.  
    90.         ProgressText.text = patcher.FetchLog();
    91.  
    92.         if (patcher.Result == PatchResult.AlreadyUpToDate)
    93.         {
    94.             PatchUIElements.SetActive(false);
    95.             LoginUIElements.SetActive(true);
    96.         }
    97.  
    98.         else if(patcher.Result == PatchResult.Success)
    99.         {
    100.             InfoText.text = "Downloading new updates";
    101.             RunPatcher();
    102.         }
    103.  
    104.         else
    105.         {
    106.             Debug.LogError("Error: " + patcher.FailDetails);
    107.         }
    108.     }
    109.  
    110.     /// <summary>
    111.     /// Runs the patcher to update application
    112.     /// </summary>
    113.     private void RunPatcher()
    114.     {
    115.         if(patcher != null && !patcher.IsRunning && patcher.Operation == PatchOperation.CheckingForUpdates && patcher.Result == PatchResult.Success)
    116.         {
    117.             Debug.Log("Patcher will start running soon.");
    118.             if (patcher.Run(false))
    119.             {
    120.                 Debug.Log("Patcher started");
    121.                 StartCoroutine(ProgressUpdater(patcher.FetchProgress()));
    122.             }
    123.         }
    124.     }
    125.  
    126.     private IEnumerator ProgressUpdater(IOperationProgress progress)
    127.     {
    128.         Debug.Log("Is progress null? " + (progress == null));
    129.         while (progress != null)
    130.         {
    131.             PercentageText.text = progress.Percentage + " %";
    132.             ProgressText.text = patcher.FetchLog();
    133.             yield return null;
    134.  
    135.             progress = patcher.FetchProgress();
    136.         }
    137.  
    138.         InfoText.text = "Applications requires restart.";
    139.      
    140.     }
    141. }
    142.  
    I'm not familiar with this field and have zero idea what mistake I might be doing. Thanks for the help.
     
  31. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,865
    Hi,

    1. patcher.FetchProgress returns an IOperationProgress instance only if the patcher is currently downloading a file or applying a binary diff. As you are calling this function immediately after running the patcher, it is most likely that the patcher is not yet doing any of these operations
    2. You must use a self patcher executable and call patcher.Run(true), if your app is patching itself
    3. Here's a modified version of your code that is supposed to work:

    Code (CSharp):
    1. using System.Collections;
    2. using UnityEngine;
    3. using SimplePatchToolCore;
    4. using SimplePatchToolUnity;
    5. using SimplePatchToolSecurity;
    6. using System.IO;
    7. using TMPro;
    8.  
    9. public class PatchToolScript : MonoBehaviour
    10. {
    11.     void Awake()
    12.     {
    13.         InitializePatcher( Path.GetDirectoryName( PatchUtils.GetCurrentExecutablePath() ), VersionInfoURL );
    14.     }
    15.  
    16.     [Header( "Patcher Parameters" )]
    17.     [SerializeField]
    18.     private string VersionInfoURL;
    19.  
    20.     [Header( "XML Verifier Keys (Optional)" )]
    21.     [SerializeField]
    22.     [TextArea]
    23.     [Tooltip( "Public RSA key that will be used to verify downloaded VersionInfo'es" )]
    24.     private string versionInfoRSA;
    25.  
    26.     [SerializeField]
    27.     [TextArea]
    28.     [Tooltip( "Public RSA key that will be used to verify downloaded PatchInfo'es" )]
    29.     private string patchInfoRSA;
    30.  
    31.     [Header( "UI Elements" )]
    32.     [SerializeField]
    33.     private TMP_Text InfoText;
    34.  
    35.     [SerializeField]
    36.     private TMP_Text PercentageText;
    37.  
    38.     [SerializeField]
    39.     private TMP_Text ProgressText;
    40.  
    41.     [SerializeField]
    42.     private GameObject PatchUIElements;
    43.  
    44.     [SerializeField]
    45.     private GameObject LoginUIElements;
    46.  
    47.     private SimplePatchTool patcher;
    48.  
    49.     /// <summary>
    50.     /// Initializes the patcher
    51.     /// </summary>
    52.     /// <param name="rootPath"> The path of the executable path </param>
    53.     /// <param name="versionInfoURL"> Url of the versioninfo.info</param>
    54.     private void InitializePatcher( string rootPath, string versionInfoURL )
    55.     {
    56.         patcher = SPTUtils.CreatePatcher( rootPath, versionInfoURL ).UseRepairPatch( true ).UseIncrementalPatch( true ).LogProgress( true );
    57.  
    58.         if( !string.IsNullOrEmpty( versionInfoRSA ) )
    59.             patcher.UseVersionInfoVerifier( ( ref string xml ) => XMLSigner.VerifyXMLContents( xml, versionInfoRSA ) );
    60.  
    61.         if( !string.IsNullOrEmpty( patchInfoRSA ) )
    62.             patcher.UsePatchInfoVerifier( ( ref string xml ) => XMLSigner.VerifyXMLContents( xml, patchInfoRSA ) );
    63.  
    64.         CheckForUpdates();
    65.     }
    66.  
    67.     /// <summary>
    68.     /// Checks for new updates and modifies UI appropriately
    69.     /// </summary>
    70.     private void CheckForUpdates()
    71.     {
    72.         InfoText.text = "Checking for updates";
    73.  
    74.         if( patcher.CheckForUpdates( false ) )
    75.             StartCoroutine( WaitingForCheckToComplete() );
    76.     }
    77.  
    78.     /// <summary>
    79.     /// Enumerator that continues to check for updates
    80.     /// </summary>
    81.     /// <returns></returns>
    82.     private IEnumerator WaitingForCheckToComplete()
    83.     {
    84.         while( patcher.IsRunning )
    85.         {
    86.             FetchLogs();
    87.             yield return null;
    88.         }
    89.  
    90.         FetchLogs();
    91.  
    92.         if( patcher.Result == PatchResult.AlreadyUpToDate )
    93.         {
    94.             PatchUIElements.SetActive( false );
    95.             LoginUIElements.SetActive( true );
    96.         }
    97.         else if( patcher.Result == PatchResult.Success )
    98.         {
    99.             InfoText.text = "Downloading new updates";
    100.             RunPatcher();
    101.         }
    102.         else
    103.             Debug.LogError( "Error: " + patcher.FailDetails );
    104.     }
    105.  
    106.     /// <summary>
    107.     /// Runs the patcher to update application
    108.     /// </summary>
    109.     private void RunPatcher()
    110.     {
    111.         if( patcher != null && !patcher.IsRunning && patcher.Operation == PatchOperation.CheckingForUpdates && patcher.Result == PatchResult.Success )
    112.         {
    113.             Debug.Log( "Patcher will start running soon." );
    114.             if( patcher.Run( true ) )
    115.             {
    116.                 Debug.Log( "Patcher started" );
    117.                 StartCoroutine( ProgressUpdater() );
    118.             }
    119.         }
    120.     }
    121.  
    122.     private IEnumerator ProgressUpdater()
    123.     {
    124.         while( patcher.IsRunning )
    125.         {
    126.             FetchLogs();
    127.             yield return null;
    128.         }
    129.  
    130.         FetchLogs();
    131.  
    132.         if( patcher.Result == PatchResult.AlreadyUpToDate )
    133.         {
    134.             PatchUIElements.SetActive( false );
    135.             LoginUIElements.SetActive( true );
    136.         }
    137.         else if( patcher.Result == PatchResult.Success )
    138.         {
    139.             // Here, you should run the self patcher executable to finalize the patch because we are self patching the app
    140.             InfoText.text = "Application will now restart.";
    141.  
    142.             // In this instance, wait for 4 seconds before running the self patcher executable
    143.             yield return new WaitForSecondsRealtime( 4f );
    144.             patcher.ApplySelfPatch( SPTUtils.SelfPatcherExecutablePath, PatchUtils.GetCurrentExecutablePath() );
    145.         }
    146.         else
    147.             Debug.LogError( "Error: " + patcher.FailDetails );
    148.     }
    149.  
    150.     private void FetchLogs()
    151.     {
    152.         string log = patcher.FetchLog();
    153.         while( log != null )
    154.         {
    155.             ProgressText.text = log;
    156.             log = patcher.FetchLog();
    157.         }
    158.  
    159.         IOperationProgress progress = patcher.FetchProgress();
    160.         while( progress != null )
    161.         {
    162.             PercentageText.text = progress.Percentage + " %";
    163.             progress = patcher.FetchProgress();
    164.         }
    165.     }
    166. }
     
  32. Thimble2600

    Thimble2600

    Joined:
    Nov 27, 2015
    Posts:
    165
    Hi there, having some trouble using <BaseDownloadURL>, was hoping you could help.

    I started with a blank VersionInfo.info file with no XML what so ever.
    Using that I created my first patch, then copied the patch over to the blank VersionInfo.info
    Then I made a new patch for version 0.2. Now I'm trying to update my original versionInfo (running 0.1) to the latest patch, 0.2.

    How do I upgrade my empty VersionInfo into my first patch' VersionInfo?



    Incase my links aren't readable I'll share them here and make you can tell me.
    Master VersionInfo.info
    https://drive.google.com/open?id=1LF_oieR1hKwxQIRxRXayoiCUHe-yBiG2

    Patch 0.1
    https://drive.google.com/open?id=1V3d0T3EBb3HwevJkYaohj_DnV5euKEyX


    Also tried
    Master VersionInfo.info
    https://drive.google.com/file/d/1LF_oieR1hKwxQIRxRXayoiCUHe-yBiG2

    Patch 0.1
    https://drive.google.com/file/d/1V3d0T3EBb3HwevJkYaohj_DnV5euKEyX
     
    Last edited: Dec 16, 2018
  33. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,865
    .
     
    Last edited: May 4, 2020
  34. Thimble2600

    Thimble2600

    Joined:
    Nov 27, 2015
    Posts:
    165
    Cheers Yasirkula, you're my hero :) So excited to get this up and running!
     
    yasirkula likes this.
  35. sliptrixx

    sliptrixx

    Joined:
    Mar 24, 2016
    Posts:
    12
    Hello. I'm getting an error while downloading saying a file is corrupted. I re-processed the builds and it still shows up not completing the update. Any idea why?
     
  36. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,865
    Where are you hosting your files at? If it is Drive, is the directory holding the patch files public? You can also send me your VersionInfo.info via PM or e-mail so that I can see if there are any issues.
     
  37. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,865
    .
     
    Last edited: May 4, 2020
    hopeful, AthrunVLokiz and digiross like this.
  38. Shadowing

    Shadowing

    Joined:
    Jan 29, 2015
    Posts:
    1,647
    Thanks for making this @yasirkula Huge life saver man.
    I'm ditching the dark patcher asset I was using and in the process of inserting your patcher into the back end of my Game Browser as shown in the video below. Its a game launcher that manages all my games just like Blizzards.



    Some future suggestions.
    I haven't patched anything yet with your patcher but I was looking at the create patch editor.
    Seems we should just have to give it a single folder location.
    Then it will create some sub folders like. Previous version and Patches
    So after it does a patch have it replace the previous version with the new version. Other wise i have to manually create folders with a naming convention.
    Then inside the patches folder it will create patches like 2017.1.13. If two or more patches on the same day. 2017.1.13.1, 2017.1.13.2 etc..
    PatcherEditor.cs
    Code (csharp):
    1. window.c_Version = DateTime.Now.ToString("yyyy.MM.dd");
    Creating patches with 1.0 as an example is honestly pretty bad idea. Id change it as the example it just starts people off on bad practice. Using a date it at least provides reference to something. Also with using that you can now have a auto fill in for Project version. Just auto fill in the date. Then if the user does more than one patch that given day let them add the next .1, .2 etc..

    Your code is awesome :) Great design man. The Api is awesome. Love how I can just tap into everything.


    Edit:

    I see what you are doing now. You are grabbing the Application.Version. idk why Unity even has that lol. Guess it probably works with their version controller.

    This would be a good update too.
    I noticed my project name 26horses Browser was failing the valid check.
    This will remove spaces between words and capital the first letter of each word. It will also lower case all the other letters in the words.

    Find this code
    Code (csharp):
    1.  
    2. window.c_Name = PatchUtils.IsProjectNameValid(Application.productName) ? Application.productName : "MyProject";
    3.  
    Change with this code
    Code (csharp):
    1. string ProjectName = System.Threading.Thread.CurrentThread.CurrentCulture.TextInfo.ToTitleCase(Application.productName.ToLower()).Replace(" ", string.Empty);
    2. window.c_Name = PatchUtils.IsProjectNameValid(ProjectName) ? ProjectName : "MyProject";
    3.  
    4.  
     
    Last edited: Jan 13, 2019
    yasirkula and hopeful like this.
  39. hopeful

    hopeful

    Joined:
    Nov 20, 2013
    Posts:
    5,676
    That's a nice looking gizmo you've cooked up there. Good job! :)
     
    Shadowing likes this.
  40. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,865
    @Shadowing Thank you very much for your suggestions, every feedback is welcome.

    To be honest, I think version numbers like 1.0 or 0.6.1.0 are more appropriate because that's how apps in common represent their version numbers. Using dates for version numbers sounds a bit odd to me. But dates can be used as directory names, that's totally reasonable; which brings us to your other suggestion: letting SimplePatchTool handle all the file organization stuff automatically.

    I've thought about this, as well. But I wanted to give users complete freedom over where and how they store their patch files and etc. However, I might as well create a separate SimplePatchTool window that works just like that and just takes the path of the main directory as parameter.

    Again, thank you for your suggestions!
     
  41. hopeful

    hopeful

    Joined:
    Nov 20, 2013
    Posts:
    5,676
    I'm undecided on a numbering system for myself yet, but a top level version number followed by a date (YYMMDD) possibly followed by an ordinal patch number sounds like it might be very readable.
     
  42. Shadowing

    Shadowing

    Joined:
    Jan 29, 2015
    Posts:
    1,647
    I ran into a issue last night. When I created a patch in the editor the log stopped showing the progress of the patch.
    The patch did finish though cause the info file was created.

    I have a theory its from exiting out of the patcher window during the patch.

    It never showed these 5 lines at the end.
    Code (csharp):
    1.  
    2. ...Patch created in 250.164 seconds...
    3. Compression ratio is 30.98%
    4. ...Writing version info to XML...
    5. ...Done...
    6. Operation successful..
    7.  
    Pretty sure it stopped logging even before that though.
    Wish there was a option to not have compression. So patches would be much faster.
    Or 3 levels of compression. Off, Moderate and High.
    Patches are pretty small in size anyways.

    My last patcher i could create a patch in 30 seconds with compression.
    255mb to 105mb

    This patcher takes me 3.8 minutes.
    255mb to 79.1mb

    So this compression is much higher compression. It probably takes an extra 3 minutes to reduce it that other 30 mb though. But id still like have the max compression for huge first versions though.
     
    Last edited: Jan 15, 2019
  43. Shadowing

    Shadowing

    Joined:
    Jan 29, 2015
    Posts:
    1,647
    what does the create repair patch check box do on create a patch window?
    Is that to create a new version and not a patch?
    Or is for giving me a bolean to read in my logic to force the client to do a repair?

    another thing to is there no way to read the patch version when it checks for a patch?
    wish i could do something like patch.version or something.
     
  44. Shadowing

    Shadowing

    Joined:
    Jan 29, 2015
    Posts:
    1,647
    Sorry for all my posts lol.
    This is just some work flow I want to share.

    It seems it would be easier to import Simple Patch Tool on the Launcher and on the Game.
    Then set your links in the create tab to dirty so it saves it.
    so you never have to reselect directories or change any links.
    This saves a lot of time. You don't have to load the Launcher every time you do a game patch.
    I've been doing patches for 3 years now and trust me it gets super old closing your game out and loading the Launcher to do a patch. :)

    Since now the links never change cause you are only patching one project.
    You can click patch and it auto adds the <BaseDownloadURL> link in the info file.


    Here is a better idea that would be faster for upgrades

    New builds goes to P:/Builds/Launcher/Windows/
    My Output path goes to P:/Versions/Launcher/Windows/Patches

    This is how I do the Previous path.
    • Delete the build if there is one in the Previous Build folder P:/Versions/Launcher/Windows/Previous Build/
    • Copy my build from P:/Builds/Launcher/Windows/ to P:/Versions/Launcher/Windows/Previous Build/ Each time I do a new build.

    This creates a easier way to upgrade Simple Patcher Tool with this logic. Instead of creating some more complex version control.
    A drop down box could be added for Platform, Windows, Mac and Linux which will just simply string sniff and replace Windows in all the path with the platform.

    so just to add some thoughts.
     
    Last edited: Jan 15, 2019
  45. Shadowing

    Shadowing

    Joined:
    Jan 29, 2015
    Posts:
    1,647
    Wish there was a way to see the percentage progress while it downloads each individual file.
    This way I can show a smaller progress bar.

    As shown in the picture. I fill the center triangle for over all percentage and I darken the fill of the outer triangle for each individual file.




    Any chance you can release a version that doesn't have compiled dll files? Im not sure how to do it using Git and Visual Studio.
    Course it probably doesn't even matter atm. My Csharp is no where good enough to even edit it maybe idk. I found where it downloads the file with a web request though on CookieAwareWebClient.cs I'm gonna create a static variable and try to use that.

    It looks like the event OnDownloadFileProgressChange needs to be extended to add DownloadProgress to it. Then even better have it add to the IOperationProgress class so it can be fetched through patcher.FetchProgress. But all that is compiled i guess. :(

    The issue talking about this error on git. This happens to me as well
    https://github.com/yasirkula/UnitySimplePatchTool/issues/2
    happens everytime now actually. Says permission issue to the folder but when clicking create patch again it works. I believe it won't happen on a fresh load of the Launcher. I have a theory maybe the software opens up the folder during a patch and then when you try to create a 2nd patch maybe it still has the folder open and it never closed it? Which gives it a permission error idk. So was thinking its locking the folder and clicking create patch again unlocks it. I think it does it also everytime if you have one of the input fields focused on the editor window.
     
    Last edited: Jan 17, 2019
  46. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,865
    @Shadowing Thank you for all the valuable feedback, I appreciate it.

    - I'll see if closing the Simple Patch Tool window will have any other negative effects on the patcher
    - I am aware of the long compression times, maybe I can add some ways to use custom compression algorithms or to get rid of the compression altogether
    - Disabling the "Create repair patch" toggle allows you to create only an incremental patch. It is only useful if you don't want to use repair patch while patching your app (not recommended)
    - I plan to add some callback methods to SimplePatchTool, one of which will let you know the version code of the new version
    - I also plan to create another Simple Patch Tool window that will handle most of the directory organization stuff and remember your choices, which should make it easier to create patches in most circumstances
    - patcher.FetchProgress fetches the progress of the currently downloaded file. It is not possible to fetch the overall progress at the moment. So, seems like you were using the progress in the wrong progress bar :D
    - You can clone the SimplePatchTool repository to make modifications to SimplePatchTool.dll whenever you feel ready
    - Do you encounter the same issue when you point the output directory to some directory that you've never used with SimplePatchTool before? Are you testing it on Windows or another OS?
     
  47. Shadowing

    Shadowing

    Joined:
    Jan 29, 2015
    Posts:
    1,647
    Haha well crap. :)
    I noticed it shows the download amount in Megabytes in the string of the progress for each file.
    I could read the folder memory size of the incremental folder and then grab the file size from that string and figure out a over all progress percentage.
    Would the incremental folder size equal to the same being downloaded?

    Edit: Actually I could just use this for the over all progress percentage. The 132/196
    132/196 Downloading: System Lords_Data\Managed\UnityEngine.SpriteMaskModule.xml (0.00MB)

    So i'll just show files being processed instead of megabytes. That would be good enough I think. I think thats what my last patcher I used did anyways.
     
  48. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,865
    To get detailed information about the download progress without using string operations, you can use the following code:

    Code (CSharp):
    1. DownloadProgress download = patcher.FetchProgress() as DownloadProgress;
    2. if( download != null )
    3. {
    4.     // See: https://github.com/yasirkula/SimplePatchTool/blob/master/SimplePatchToolCore/Communications/PatchProgressInfo.cs
    5. }
    You can't really predict the total download size by looking at the incremental patch directory's size because that directory may contain several patches but the client will download only the patches that they need (i.e. 1.2 version of the app won't download the 1.0->1.1 or 1.1->1.2 incremental patches).

    Total percentage is in my to-do list, I'd recommend you not to implement it in your app for now.
     
    hopeful likes this.
  49. Shadowing

    Shadowing

    Joined:
    Jan 29, 2015
    Posts:
    1,647
    Ya I understand all that now since you told me incremental folder appends :)
    I don't see where DownloadProgress method returns the file count
    56/192

    if im understanding the code correctly. Only these things get returned.
    Code (csharp):
    1.  
    2. return Localization.Get( StringId.DownloadingXProgressInfo, Filename, FileDownloadedSize.ToMegabytes(), FileTotalSize.ToMegabytes(), SpeedPretty ); } }
    3.  
     
  50. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,865
    DownloadInfo holds information like downloaded file size, download speed and etc. but not the file count; there is no public API to fetch that number. Currently, the only way to access that number is by parsing the log string. Can't you add overall progress bar support to your app in a later update?