Search Unity

  1. We would like to hear your feedback about Unity and our products. Click here for more information.
    Dismiss Notice

SimplePatchTool - open source patching solution for standalone platforms

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

  1. Shadowing

    Shadowing

    Joined:
    Jan 29, 2015
    Posts:
    1,165
    Showing over all progess using file count worked out pretty well. I understand its not a accurate progress bar. Well actually it is just not how a normal would work ha.
    download is always null though. i was gonna show the current file being processed.


    Code (csharp):
    1.  
    2.        private void FetchLogsFromPatcher(){
    3.             string log = patcher.FetchLog();
    4.             while(log != null){
    5.                 if(GameSettings.patcherLog){
    6.                     Debug.Log(log);
    7.                      if(log.Contains("/")) {
    8.                         string logString = log.Split(' ').First().Trim();
    9.                         string[] strArray = logString.Split('/');
    10.                         float OverallPercentage = (float)int.Parse(strArray[0]) / int.Parse(strArray[1]);
    11.                         ProgressText.text = Mathf.FloorToInt(OverallPercentage * 100)+"%";
    12.                         Progress.fillAmount = OverallPercentage;
    13.                     }
    14.          
    15.                     log = patcher.FetchLog();
    16.                 }
    17.             }
    18.             IOperationProgress progress = patcher.FetchProgress();
    19.             DownloadProgress download = patcher.FetchProgress() as DownloadProgress;
    20.      
    21.             while(progress != null){
    22.                 if(GameSettings.patcherLog){
    23.                     Debug.Log(string.Concat(progress.Percentage, "% ", progress.ProgressInfo));
    24.                 }
    25.                     if(download != null){
    26.                         Status.text = "Processing file "+download.Filename;
    27.                     }
    28.                     FileProgress.fillAmount = (float)progress.Percentage / 100;
    29.          
    30.                     progress = patcher.FetchProgress();
    31.             }
    32.         }
    33.  
    A video showing this. Of course real progress would be better. This should be good until you do a update later on. At least players can see something atm.

     
    Last edited: Jan 20, 2019
    yasirkula and hopeful like this.
  2. Shadowing

    Shadowing

    Joined:
    Jan 29, 2015
    Posts:
    1,165
    Turns out the launcher has to be ran in admin mode to patch it self :(
    No issues when patching the game though.
    Access to C:\Program Files\26horses\ is forbidden.

    I don't understand why it needs admin rights when patching C:\Program Files\26horses\Games\
    works just fine.

    Edit: sweet I fixed that issue. I just had to tell my installer to run the launcher as admin mode

    Edit Again lol: Turns out if I tell my installer to or not to run as admin mode it will patch the patcher with no issue. I think its just because a window pops up giving permission to make changes and its the same system that auto runs the Launcher after the install.
    Then if i close the Launcher and open it up manually it the patcher will fail patching it self.
    So I guess the run as admin mode option isn't working on my installer.

    but thats not really a option though. That means a window will pop up asking for permission every single time a player excutes the launcher.
     
    Last edited: Jan 20, 2019
  3. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    925
    Yeah that sounds odd but patcher requests admin permissions only when it can't create a temporary file inside that directory. For example, try saving a dummy text file inside that directory with Notepad and see if it succeeds.

    BTW, it is probable that the installer will launch the launcher in admin mode only the first time. On consequent launches, patcher may still require admin permissions.
     
  4. Shadowing

    Shadowing

    Joined:
    Jan 29, 2015
    Posts:
    1,165
    wonder if it would fix it if the temp folder was saved in Application.persistentDataPath instead?
    ya i had to save a auto_login text file in Application.persistentDataPath to fix that issue.
     
  5. Shadowing

    Shadowing

    Joined:
    Jan 29, 2015
    Posts:
    1,165
    Interesting if I install the launcher in My Documents lol. There is no permission issues.
    actually i can just move the Launcher folder around into different folders testing this super fast.
    Its only Program Files that gives this problem.

    Also I'm able to get it to install in C:/26horses with on permisison issues.
    That may be better than my documents. Now i know why i see some software install there stuff there. Cause there were faced with the permission issue.

    If you are saying the permission issue is from the temp folder. I bet putting the temp folder in appData will fix the permission issues. Maybe lol.

    Also I was just thinking the other day. I should be able to let people choose where Games are installed at.
    Seems its not bound to relative path?
    You are giving it a absolute path here.
    I think you are anyways. I didn't Debug.Log what PatchUtils.GetCurrentExecutablePath() is returning.

    Code (csharp):
    1.  
    2. InitializePatcher(Path.Combine( Path.GetDirectoryName(PatchUtils.GetCurrentExecutablePath()), GameSettings.GamesDirectory+name), GameWebPath);
    3.  
     
    Last edited: Jan 20, 2019
  6. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    925
    I use a temporary file to test the permission only, I write temporary files to a temporary directory already :) If I can't write a temporary file to application directory, then I can't update the files in there either.

    P.S. Yes, your launcher can install its games to anywhere you want.
    P.P.S.
    PatchUtils.GetCurrentExecutablePath()
    will return the path of the launcher executable (the running application itself) in your case.
     
  7. Shadowing

    Shadowing

    Joined:
    Jan 29, 2015
    Posts:
    1,165
    I don't understand why the programs file is so dang permission sensitive. Its a bunch of crap:(
    So I guess what I need to do some time in the future.

    • Store games in another folder. Let user select that but don't let them select the programs folder. (Probably do this in the spring time or summer)
    • Figure out how to get the permissions window top pop up for the user when patching the launcher. (A year and half from now probably. Maybe you will update it to do that by then hehe :) )

    The launcher doesn't get updates often anyways. The news feed and patch notes etc.. is all loaded in from the data base and updated through another piece of software.
    I would think getting that window to pop up. The launcher shouldn't need to restart. Only when finish patching.

    For now im installing the patcher right off the C drive. Will get me by for a little while.
    The patcher works amazing @yasirkula and Id like to thank you a ton for helping get it integrated into my Launcher. You're a good man! Now its time for me to get back to working on game developement :) cheers!

    Edit: Actually I'm installing it in the AppsData folder. I'm using a new installer now that lets me do that.
     
    Last edited: Jan 22, 2019
    yasirkula likes this.
  8. Shadowing

    Shadowing

    Joined:
    Jan 29, 2015
    Posts:
    1,165
    I wanted to share this installer I found.
    I've tried a ton of installers over the last few years and finally found the perfect one. Its so good. Cost about $69. Its also free to try.
    Also provides a modern look and can customize it a little.

    https://www.actualinstaller.com/



    Also here is a little script I use for windows builds to make the launcher be borderless.


    Code (csharp):
    1.  
    2. using UnityEngine;
    3. using System;
    4. using System.Runtime.InteropServices;
    5. using System.Text;
    6.     /// <summary>
    7.     /// Attach this script to any Game Object to make your build window borderless. Warning! This only works on Windows and might be unstable.
    8.     /// </summary>
    9.     public class BorderlessWindow : MonoBehaviour
    10.     {
    11.         /// <summary>
    12.         /// Height of draggable area. Set <c>0.0f</c> to make draggable whole window.
    13.         /// </summary>
    14.         [Header("Height of draggable area. Set 0.0 or less to make draggable whole window.")]
    15.         public float titleBarHeight = 40.0f;
    16. #if UNITY_STANDALONE_WIN
    17.         #region Windows
    18.         internal const string UnityWindowClassName = "UnityWndClass";
    19.         [DllImport("user32.dll", EntryPoint = "SetWindowLong", SetLastError = true, CharSet = CharSet.Auto)]
    20.         internal static extern IntPtr SetWindowLongPtr(IntPtr hWnd, int nIndex, int dwNewLong);
    21.         [DllImport("user32.dll")]
    22.         internal static extern int GetSystemMetrics(int smIndex);
    23.         [DllImport("user32.dll", EntryPoint = "GetWindowLong", SetLastError = true, CharSet = CharSet.Auto)]
    24.         internal static extern IntPtr GetWindowLongPtr(IntPtr hWnd, int nIndex);
    25.         [DllImport("user32.dll")]
    26.         internal static extern IntPtr SetWindowLong(IntPtr hwnd, int _nIndex, int dwNewLong);
    27.         [DllImport("user32.dll")]
    28.         internal static extern bool SetWindowPos(IntPtr hWnd, int hWndInsertAfter, int X, int Y, int cx, int cy,
    29.             uint uFlags);
    30.         [DllImport("user32.dll")]
    31.         [return: MarshalAs(UnmanagedType.Bool)]
    32.         static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
    33.         [DllImport("kernel32.dll")]
    34.         internal static extern uint GetCurrentThreadId();
    35.         [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    36.         internal static extern int GetClassName(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
    37.         internal delegate bool EnumWindowsProc(IntPtr hWnd, IntPtr lParam);
    38.         [DllImport("user32.dll")]
    39.         [return: MarshalAs(UnmanagedType.Bool)]
    40.         internal static extern bool EnumThreadWindows(uint dwThreadId, EnumWindowsProc lpEnumFunc, IntPtr lParam);
    41.         [StructLayout(LayoutKind.Sequential)]
    42.         internal struct POINT
    43.         {
    44.             public int X;
    45.             public int Y;
    46.             public static implicit operator Vector2(POINT point)
    47.             {
    48.                 return new Vector2(point.X, point.Y);
    49.             }
    50.         }
    51.         [DllImport("user32.dll")]
    52.         internal static extern bool GetCursorPos(out POINT lpPoint);
    53.         internal const int
    54.             SWP_FRAMECHANGED = 0x0020,
    55.             SWP_NOMOVE = 0x0002,
    56.             SWP_NOSIZE = 0x0001,
    57.             SWP_NOZORDER = 0x0004,
    58.             SWP_NOOWNERZORDER = 0x0200,
    59.             SWP_SHOWWINDOW = 0x0040,
    60.             SWP_NOSENDCHANGING = 0x0400;
    61.         internal const int GWL_STYLE = -16;
    62.         internal const int SW_MAXIMIZE = 3;
    63.         internal const int SW_MINIMIZE = 6;
    64.         internal const int
    65.             WS_BORDER = 0x00800000,
    66.             WS_CAPTION = 0x00C00000,
    67.             WS_CHILD = 0x40000000,
    68.             WS_CHILDWINDOW = 0x40000000,
    69.             WS_CLIPCHILDREN = 0x02000000,
    70.             WS_CLIPSIBLINGS = 0x04000000,
    71.             WS_DISABLED = 0x08000000,
    72.             WS_DLGFRAME = 0x00400000,
    73.             WS_GROUP = 0x00020000,
    74.             WS_HSCROLL = 0x00100000,
    75.             WS_ICONIC = 0x20000000,
    76.             WS_MAXIMIZE = 0x01000000,
    77.             WS_MAXIMIZEBOX = 0x00010000,
    78.             WS_MINIMIZE = 0x20000000,
    79.             WS_MINIMIZEBOX = 0x00020000,
    80.             WS_OVERLAPPED = 0x00000000,
    81.             WS_OVERLAPPEDWINDOW =
    82.                 WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,
    83.             WS_POPUP = unchecked((int) 0x80000000),
    84.             WS_POPUPWINDOW = WS_POPUP | WS_BORDER | WS_SYSMENU,
    85.             WS_SIZEBOX = 0x00040000,
    86.             WS_SYSMENU = 0x00080000,
    87.             WS_TABSTOP = 0x00010000,
    88.             WS_THICKFRAME = 0x00040000,
    89.             WS_TILED = 0x00000000,
    90.             WS_TILEDWINDOW = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,
    91.             WS_VISIBLE = 0x10000000,
    92.             WS_VSCROLL = 0x00200000;
    93.         internal IntPtr _WINDOWS_HANDLE_ = IntPtr.Zero;
    94.         internal static class Flags
    95.         {
    96.             public static void Set<T>(ref T mask, T flag) where T : struct
    97.             {
    98.                 int maskValue = (int) (object) mask;
    99.                 int flagValue = (int) (object) flag;
    100.                 mask = (T) (object) (maskValue | flagValue);
    101.             }
    102.             public static void Unset<T>(ref T mask, T flag) where T : struct
    103.             {
    104.                 int maskValue = (int) (object) mask;
    105.                 int flagValue = (int) (object) flag;
    106.                 mask = (T) (object) (maskValue & (~flagValue));
    107.             }
    108.             public static void Toggle<T>(ref T mask, T flag) where T : struct
    109.             {
    110.                 if (Contains(mask, flag))
    111.                 {
    112.                     Unset(ref mask, flag);
    113.                 }
    114.                 else
    115.                 {
    116.                     Set(ref mask, flag);
    117.                 }
    118.             }
    119.             public static bool Contains<T>(T mask, T flag) where T : struct
    120.             {
    121.                 return Contains((int) (object) mask, (int) (object) flag);
    122.             }
    123.             public static bool Contains(int mask, int flag)
    124.             {
    125.                 return (mask & flag) != 0;
    126.             }
    127.         }
    128.         internal void WindowsAwake()
    129.         {
    130.             Application.runInBackground = true;
    131.             uint threadId = GetCurrentThreadId();
    132.             EnumThreadWindows(threadId, (hWnd, lParam) =>
    133.             {
    134.                 var classText = new StringBuilder(UnityWindowClassName.Length + 1);
    135.                 GetClassName(hWnd, classText, classText.Capacity);
    136.                 if (classText.ToString() == UnityWindowClassName)
    137.                 {
    138.                     _WINDOWS_HANDLE_ = hWnd;
    139.                     return false;
    140.                 }
    141.                 return true;
    142.             }, IntPtr.Zero);
    143.         }
    144.         internal void WindowsUpdate()
    145.         {
    146.             int flags = (int) GetWindowLongPtr(_WINDOWS_HANDLE_, GWL_STYLE);
    147.             Flags.Unset(ref flags, WS_CAPTION);
    148.             SetWindowLongPtr(_WINDOWS_HANDLE_, GWL_STYLE, flags);
    149.             SetWindowPos(_WINDOWS_HANDLE_, -2, (int) windowRect.x, (int) windowRect.y, (int) windowRect.width,
    150.                 (int) windowRect.height, SWP_FRAMECHANGED);
    151.             SetWindowLongPtr(_WINDOWS_HANDLE_, GWL_STYLE, flags);
    152.             SetWindowLongPtr(_WINDOWS_HANDLE_, GWL_STYLE, flags);
    153.         }
    154.         internal static Vector2 GetCursorPosition()
    155.         {
    156.             POINT lpPoint;
    157.             GetCursorPos(out lpPoint);
    158.             return lpPoint;
    159.         }
    160.         internal Vector2 GetScreenResoultion()
    161.         {
    162.             Vector2 r = new Vector2();
    163.             r.x = GetSystemMetrics(78);
    164.             r.y = GetSystemMetrics(79);
    165.             return r;
    166.         }
    167.         #endregion
    168.         internal Rect windowRect;
    169.         internal bool isDragged;
    170.         internal Vector2 dragStartPosition;
    171.         internal Vector2 dragWindowStartPosition;
    172.         protected virtual void Awake()
    173.         {
    174.             if (!Application.isEditor)
    175.             {
    176.                 windowRect.position = new Vector2(Screen.currentResolution.width/2.0f - Screen.width/2.0f,
    177.                     Screen.currentResolution.height/2.0f - Screen.height/2.0f);
    178.                 //windowRect.size = new Vector2(Screen.width, Screen.height);
    179.                 windowRect.size = new Vector2(1280, 720);
    180.                 if (Application.platform == RuntimePlatform.WindowsPlayer)
    181.                 {
    182.                     WindowsAwake();
    183.                 }
    184.             }
    185.         }
    186.         protected virtual void Update()
    187.         {
    188.             if (!Application.isEditor)
    189.             {
    190.                 if (Input.GetMouseButton(0) && isDragged)
    191.                 {
    192.                     Vector2 translation = dragStartPosition - GetCursorPosition();
    193.                     windowRect.position = dragWindowStartPosition - translation;
    194.                 }
    195.                 else if (Input.GetMouseButtonDown(0) && (titleBarHeight <= 0.0f || Input.mousePosition.y > (Screen.height - titleBarHeight)))
    196.                 {
    197.                     dragStartPosition = GetCursorPosition();
    198.                     dragWindowStartPosition = windowRect.position;
    199.                     isDragged = true;
    200.                 }
    201.                 else
    202.                     isDragged = false;
    203.                 Vector2 screenMax = GetScreenResoultion();
    204.                 screenMax.x -= Screen.width;
    205.                 screenMax.y -= Screen.height;
    206.                 windowRect.position = new Vector2(Mathf.Clamp(windowRect.position.x, 0.0f, screenMax.x),
    207.                     Mathf.Clamp(windowRect.position.y, 0.0f, screenMax.y));
    208.                 if (Application.platform == RuntimePlatform.WindowsPlayer)
    209.                 {
    210.                     WindowsUpdate();
    211.                 }
    212.             }
    213.         }
    214.         public void MinimizeWindow(){
    215.             if (Application.platform == RuntimePlatform.WindowsPlayer){
    216.                 ShowWindow(_WINDOWS_HANDLE_, SW_MINIMIZE);
    217.             }
    218.         }
    219.         public void CloseWindow(){
    220.             #if UNITY_EDITOR
    221.             UnityEditor.EditorApplication.isPlaying = false;
    222.             #else
    223.                 Application.Quit();
    224.             #endif
    225.         }
    226. #endif
    227.     }
    228.  
    229.  
    Also I realized i could make a pause button really easy for Simple Patch Tool.
    I tested it a little bit. Seems to work fine. I paused it in the middle of downloading a single file too.


    Code (csharp):
    1.  
    2.         public void Pause(Text PauseText) {
    3.      
    4.             if(Time.timeScale == 0) {
    5.                 Time.timeScale = 1;
    6.                 PauseText.text = "Pause";
    7.             }else{
    8.                 Time.timeScale = 0;
    9.                 PauseText.text = "UnPause";
    10.             }
    11.         }
    12.  
     
    Last edited: Jan 22, 2019
    yasirkula and hopeful like this.
  9. hopeful

    hopeful

    Joined:
    Nov 20, 2013
    Posts:
    4,816
    Maybe I'm not thinking clearly, but do we need an installer in addition to a launcher / patcher? Seems like a person just downloads the launcher and that handles the install ... right?
     
  10. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    925
    @Shadowing Thank you for the borderless window script! Unless timeScale pauses UnityWebRequest, it shouldn't be possible to pause the patcher via timeScale because patcher runs on a separate thread. Currently, there is no official way to pause the patcher.

    @hopeful An installer is not needed. But it can be useful if you'd like to compress the launcher into an installer, create a shortcut on the desktop or create an item in Start menu.
     
  11. Shadowing

    Shadowing

    Joined:
    Jan 29, 2015
    Posts:
    1,165
    Ya i was surprised it worked. I paused it a few times. making sure it was in the middle of a file downloading.
    I'll create a forum post about it asking some information on that. I can't seem to find anything with google.

    The borderless script works pretty well. It does take a hair of a second to switch to borderless though. If you blink you won't see it. I believe this can be fixed later by running the script before the scene starts to load. I'll experiment with that more in a few months.

    Idk id still use an installer. The one I linked is free to use. It just doesn't allow you to customize a few things.
    This way your players just have to click on one file and hit ok and it installs it and adds the short cuts for them etc..
    Super easy to use. Make sure to have it install in the apps data folder so there are no permission issues.
     
    Last edited: Jan 25, 2019
    hopeful likes this.
  12. slava_pankratov

    slava_pankratov

    Joined:
    Jan 17, 2015
    Posts:
    41
    hey! could you add come basic flow for the admin to upload diffs to the server? Is there also a chance you can add a sample for a multy-game launcher where the user can see a list of several games and can then patch any of the if necessary? Thanks for great asset!
     
  13. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    925
    Hi! I don't plan to add a FTP uploader to the plugin yet because I believe using a dedicated app like FileZilla for this task is more appropriate and secure.

    Regarding the launcher, I may add such an example, yes. Thank you for the idea.
     
  14. Shadowing

    Shadowing

    Joined:
    Jan 29, 2015
    Posts:
    1,165
    @yasirkula Hey I was wondering in your next update if you could move Simple Patch Tool out of the Windows Menu in the editor and put it under Tools?

    I'm currently going around to all the developers and asking if they will move their assets as well.
    There is enough stuff under Windows anyways.

    These huge Asset store developers are all using Tools.
    Odin
    Natural Manufacture
    Opisve
     
  15. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    925
  16. Shadowing

    Shadowing

    Joined:
    Jan 29, 2015
    Posts:
    1,165
    Ya I already changed it. Idk man there is a heck of a lot of space on the Main menu bar. Only covers 1/3 of my screen.
    The idea is to create a global standard. Id say the benefits out weighs the few using only Simple Patch Tool though.
    If i convince enough developers to do this then it will become a standard.
    I'm even getting Text Mesh Pro to move over to Tools.
     
    yasirkula likes this.
  17. oliver_unity727

    oliver_unity727

    Joined:
    Feb 4, 2019
    Posts:
    4
    I'm trying to do a selfpatcher but after downloads when I press restart game, it says "Self patcher does not exist!"
     
  18. oliver_unity727

    oliver_unity727

    Joined:
    Feb 4, 2019
    Posts:
    4
    I just realized my problem but I dont know how to create the self patcher executable for linux. Please help.
     
  19. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    925
  20. oliver_unity727

    oliver_unity727

    Joined:
    Feb 4, 2019
    Posts:
    4
    In linux, after restarting the game it says "error system.componentmodel.win32exception the system cannot find the file specified at System.Process/StarwihtShell..." please help. The game updates but after restart it doesnt open.
     
  21. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    925
    Does this error message always pop up while trying to open the game after the update, or does it pop up only once when SimplePatchTool tries to relaunch the game after a successful update? If it is the latter, does this error message show up in a native error dialog, in a console or in some sort of other UI?
     
  22. oliver_unity727

    oliver_unity727

    Joined:
    Feb 4, 2019
    Posts:
    4
    When it tries to relaunch the game.
     

    Attached Files:

  23. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    925
    Can you try changing executable.Name to executable.FullName in this line, rebuild the SelfPatcherCore project and then rebuild the SelfPatcherWinForms project (or your own self patcher executable, just make sure to use the updated SelfPatcherCore.dll library)? You'll have to create the patches anew, unfortunately.

    P.S. I don't have an installed Linux environment on my workspace and have very limited free space on my storage to install a virtual machine, so I can't test it myself at the moment.
     
  24. AngryGermanWGT

    AngryGermanWGT

    Joined:
    Mar 15, 2019
    Posts:
    5
    @yasirkula[/USER]:

    Merhaba

    I was working through your patcher tutorial video and encountered an issue that I can't seem to solve.

    Created initial and patched versions as shown on local file system. Uploaded files as shown in the video to Google Drive and made them public. When I launch PatcherDemo V100 from local file system, the app won't show the UI that a patch is available.

    However, if I use the Patcher ControlPanelDemo and enter the respective URLs, the patching UI shows and is executed. Not sure where in the process I'm making the mistake.....

    Teşekkür ederim




    Screen Shot 2019-03-18 at 8.28.42 AM.png

    Screen Shot 2019-03-18 at 8.32.19 AM.png

    Screen Shot 2019-03-18 at 8.32.45 AM.png

    Screen Shot 2019-03-18 at 8.32.45 AM.png

    Screen Shot 2019-03-18 at 8.35.16 AM.png
     

    Attached Files:

    Last edited: Mar 18, 2019
  25. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    925
    Hi!

    Did you by any chance forgot to change the Version Info URL in V100 of your app? You may also check your game's logs at ~/Library/Logs/Unity/Player.log to see if SimplePatchTool throws any meaningful error/warning messages.
     
  26. Shadowing

    Shadowing

    Joined:
    Jan 29, 2015
    Posts:
    1,165
    When I apply a patch to the Launcher. The launcher restarts but a window pops up saying installing with a progress bar before the launcher starts back up.
    I never noticed this progress bar window before.
    Not a big deal just never noticed it before. Wondering if it was suppose to remain hidden
     
  27. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    925
  28. AngryGermanTG

    AngryGermanTG

    Joined:
    Dec 21, 2018
    Posts:
    1

    Player Logs read:


    ArgumentException: ERROR: 'rootPath' can not be empty

    at SimplePatchToolCore.SimplePatchTool..ctor (System.String rootPath, System.String versionInfoURL) [0x00000] in <filename unknown>:0

    at SimplePatchToolUnity.SPTUtils.CreatePatcher (System.String rootPath, System.String versionInfoURL) [0x00000] in <filename unknown>:0

    at SimplePatchToolUnity.SelfPatchingAppDemo.InitializePatcher () [0x00000] in <filename unknown>:0

    at SimplePatchToolUnity.SelfPatchingAppDemo.Awake () [0x00000] in <filename unknown>:0

    which I'm guessing is set here creating the patch. As you can see it is not null;

    Screen Shot 2019-04-02 at 8.56.49 AM.png
     
  29. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    925
  30. AngryGermanWGT

    AngryGermanWGT

    Joined:
    Mar 15, 2019
    Posts:
    5
    I tracked it down to the same line. Is there anything I need to add?

    Logging the path
    Debug.LogError("Path : " + System.IO.Path.GetDirectoryName(PatchUtils.GetCurrentExecutablePath()));

    the path is returned as null as well;
     
  31. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    925
    Really weird. What does PatchUtils.GetCurrentExecutablePath() return? On which platform/OS are you testing?
     
  32. AngryGermanWGT

    AngryGermanWGT

    Joined:
    Mar 15, 2019
    Posts:
    5
    Debug.LogError("Path : " + PatchUtils.GetCurrentExecutablePath()); //returns the fileName (only) of the executable
    Debug.LogError("Path : " + System.IO.Path.GetDirectoryName(PatchUtils.GetCurrentExecutablePath())); //returns null

    MacOSX platform;
     
  33. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    925
    Does any of the following values hold the full path to your application:

    System.Reflection.Assembly.GetEntryAssembly().Location
    System.Reflection.Assembly.GetExecutingAssembly().Location
    System.Environment.CurrentDirectory
    Process.GetCurrentProcess().MainModule.FileName
     
  34. AngryGermanWGT

    AngryGermanWGT

    Joined:
    Mar 15, 2019
    Posts:
    5
    Code (CSharp):
    1. patcher = SPTUtils.CreatePatcher( System.Environment.CurrentDirectory, versionInfoURL ).
    2.                 UseRepairPatch( true ).UseIncrementalPatch( true ).LogProgress( true );

    we may have a winner :


    Code (CSharp):
    1. patcher = SPTUtils.CreatePatcher( System.Environment.CurrentDirectory, versionInfoURL ).
    2.                 UseRepairPatch( true ).UseIncrementalPatch( true ).LogProgress( true );
    if I change it to this the patcher works and downloads the update.

    However, when it asks to restart the app, I get a "Self patcher does not exist!" message Screen Shot 2019-04-02 at 1.48.08 PM.png
     
  35. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    925
  36. AngryGermanWGT

    AngryGermanWGT

    Joined:
    Mar 15, 2019
    Posts:
    5
  37. killakiwi

    killakiwi

    Joined:
    Sep 5, 2013
    Posts:
    16
    Hi!, Great asset!!

    I am currently using P.A.T.C.H, another unity patcher plugin, and am looking at switching over to this.
    My issue with P.A.T.C.H is that it takes a long time to download a big patch, this is because it doesn't support zipping / unzipping of patch files so must download each file separately which is much slower than downloading 1 big file.

    Do you have plans to support this?

    Thanks!
     
  38. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    925
    Incremental patches can be considered as 1 big zipped file that holds binary diffs of the changed files. I also plan to add another patch method that compresses all the files in the version into one big zip file (e.g. a launcher can download it and then unzip it to install the game). SimplePatchTool will find the patch method that will require the least bandwidth usage and use that patch method.
     
  39. killakiwi

    killakiwi

    Joined:
    Sep 5, 2013
    Posts:
    16
    Fantastic. can't wait to try it out!
     
  40. killakiwi

    killakiwi

    Joined:
    Sep 5, 2013
    Posts:
    16
    The code that reads the repair text and fills out the VersionInfo.info file seems to not work with files that spaces on them.
    There is one file in particular that is required by Unity called Game_Data\Resources\unity default resources

    It's simple enough to do it manually for one file and I may automate it in future but just letting you know :)
    Great asset!
     
  41. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    925
    I tested the code with such filenames before actually, so I'm surprised to hear that (guessing we are talking about filling the download URLs in VersionInfo). Will check it again.
     
  42. killakiwi

    killakiwi

    Joined:
    Sep 5, 2013
    Posts:
    16
    Sorry please ignore that, it was an issue with AWS. It just happened to fail on the 1 in 337 files that has spaces :)
     
    yasirkula likes this.
  43. SaVe1418

    SaVe1418

    Joined:
    Jan 29, 2017
    Posts:
    6
    Hey guys, this looks very interesting, our game is mobile only. Did somebody tested it on iOS and Android? Would it work?
     
  44. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    925
    Only Windows, Mac OS and Linux are supported, so no support for mobile.
     
  45. SaVe1418

    SaVe1418

    Joined:
    Jan 29, 2017
    Posts:
    6
    Thank you for your quick answer. Do you plan to add a mobile support?

    On a side note, I am not a programmer, so my knowledge is limited, but is there any particular reason why it does not work on mobile. From what I understood, macOS is very similar to iOS and Android is a Linux distro, so it is not the code itself, is it maybe because of the way of accessing control or network functions?

    Thank you very much in advance.
     
  46. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    925
    I don't plan to add mobile support. I don't know whether or not it is possible to update a mobile app without using asset bundles; and asset bundles can't be used to patch scripts.
     
  47. maxbrochhaus

    maxbrochhaus

    Joined:
    Nov 19, 2018
    Posts:
    2
    I have a Problem with the Patcher, at the first start it says update available. If u click on update it destroys the game. Its deletes teh game.exe and the unitycrash.exe, as well as the unityPlayer.dll. Can u help me?
     
  48. maxbrochhaus

    maxbrochhaus

    Joined:
    Nov 19, 2018
    Posts:
    2
    btw im using it with googledrive
     
  49. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    925
    Can you send your VersionInfo to me via email or private message?
     
  50. Shadowing

    Shadowing

    Joined:
    Jan 29, 2015
    Posts:
    1,165
    @yasirkula Now that I've been using this patcher for several months. I just wanted to report I haven't had a single issue with it. Super good man.

    Reading all these post. Its amazing the level of support you provide for a free asset man.
    I don't know how you do it :p
     
    Last edited: May 22, 2019
    hopeful and yasirkula like this.