1+ using System . Diagnostics ;
2+ using System . IO . Compression ;
3+ using System . Text . Json ;
4+ using HarmonyLib ;
5+ using UnityEngine ;
6+
7+ namespace PolyMod . Managers ;
8+
9+ internal static class AutoUpdate
10+ {
11+ [ HarmonyPostfix ]
12+ [ HarmonyPatch ( typeof ( StartScreen ) , nameof ( StartScreen . Start ) ) ]
13+ private static void StartScreen_Start ( )
14+ {
15+ if ( ! Plugin . config . autoUpdate ) return ;
16+ if ( Environment . GetEnvironmentVariable ( "WINEPREFIX" ) != null )
17+ {
18+ Plugin . logger . LogError ( "Autoupdate is not supported on Wine!" ) ;
19+ return ;
20+ }
21+ HttpClient client = new ( ) ;
22+ client . DefaultRequestHeaders . Add ( "User-Agent" , "PolyMod" ) ;
23+ try
24+ {
25+ var json = JsonDocument . Parse (
26+ client . GetAsync ( "https://api.github.com/repos/PolyModdingTeam/PolyMod/releases" ) . UnwrapAsync ( )
27+ . Content . ReadAsStringAsync ( ) . UnwrapAsync ( )
28+ ) ;
29+ JsonElement ? latest = null ;
30+ for ( int i = 0 ; i < json . RootElement . GetArrayLength ( ) ; i ++ )
31+ {
32+ var release = json . RootElement [ i ] ;
33+ if ( release . GetProperty ( "prerelease" ) . GetBoolean ( ) && ! Plugin . config . updatePrerelease ) continue ;
34+ latest = release ;
35+ break ;
36+ }
37+ string newVersion = latest ? . GetProperty ( "tag_name" ) . GetString ( ) ! . TrimStart ( 'v' ) ! ;
38+ if ( newVersion . IsVersionOlderOrEqual ( Plugin . VERSION ) ) return ;
39+ string os = Application . platform switch
40+ {
41+ RuntimePlatform . WindowsPlayer => "win" ,
42+ RuntimePlatform . LinuxPlayer => "linux" ,
43+ RuntimePlatform . OSXPlayer => "macos" ,
44+ _ => "unknown" ,
45+ } ;
46+ if ( os == "unknown" )
47+ {
48+ Plugin . logger . LogError ( "Unsupported platform for autoupdate!" ) ;
49+ return ;
50+ }
51+ string bepinex_url = client
52+ . GetAsync ( "https://polymod.dev/data/bepinex.txt" ) . UnwrapAsync ( )
53+ . Content . ReadAsStringAsync ( ) . UnwrapAsync ( )
54+ . Replace ( "{os}" , os ) ;
55+ void Update ( )
56+ {
57+ Time . timeScale = 0 ;
58+ File . WriteAllBytes (
59+ Path . Combine ( Plugin . BASE_PATH , "PolyMod.new.dll" ) ,
60+ client . GetAsync ( latest ? . GetProperty ( "assets" ) [ 0 ] . GetProperty ( "browser_download_url" ) . GetString ( ) ! ) . UnwrapAsync ( )
61+ . Content . ReadAsByteArrayAsync ( ) . UnwrapAsync ( )
62+ ) ;
63+ using ZipArchive bepinex = new ( client . GetAsync ( bepinex_url ) . UnwrapAsync ( ) . Content . ReadAsStream ( ) ) ;
64+ bepinex . ExtractToDirectory ( Path . Combine ( Plugin . BASE_PATH , "New" ) , overwriteFiles : true ) ;
65+ ProcessStartInfo info = new ( )
66+ {
67+ WorkingDirectory = Path . Combine ( Plugin . BASE_PATH ) ,
68+ CreateNoWindow = true ,
69+ } ;
70+ if ( Application . platform == RuntimePlatform . WindowsPlayer )
71+ {
72+ string batchPath = Path . Combine ( Plugin . BASE_PATH , "update.bat" ) ;
73+ File . WriteAllText ( batchPath , $@ "
74+ @echo off
75+ echo Waiting for Polytopia.exe to exit...
76+ :waitloop
77+ tasklist | findstr /I ""Polytopia.exe"" >nul
78+ if not errorlevel 1 (
79+ timeout /T 1 >nul
80+ goto waitloop
81+ )
82+
83+ echo Updating...
84+ robocopy ""New"" . /E /MOVE /NFL /NDL /NJH /NJS /NP >nul
85+ rmdir /S /Q ""New""
86+ del /F /Q ""BepInEx\plugins\PolyMod.dll""
87+ move /Y ""PolyMod.new.dll"" ""BepInEx\plugins\PolyMod.dll""
88+
89+ echo Launching game...
90+ start steam://rungameid/874390
91+ timeout /T 3 /NOBREAK >nul
92+ exit
93+ " ) ;
94+ info . FileName = "cmd.exe" ;
95+ info . Arguments = $ "/C start \" \" \" { batchPath } \" ";
96+ info . WorkingDirectory = Plugin . BASE_PATH ;
97+ info . CreateNoWindow = true ;
98+ info . UseShellExecute = false ;
99+ }
100+ if ( Application . platform == RuntimePlatform . LinuxPlayer || Application . platform == RuntimePlatform . OSXPlayer )
101+ {
102+ string bashPath = Path . Combine ( Plugin . BASE_PATH , "update.sh" ) ;
103+ File . WriteAllText ( bashPath , $@ "
104+ #!/bin/bash
105+
106+ echo ""Waiting for Polytopia to exit...""
107+ while pgrep -x ""Polytopia"" > /dev/null; do
108+ sleep 1
109+ done
110+
111+ echo ""Updating...""
112+ mv New/* . && rm -rf New
113+ rm -f BepInEx/plugins/PolyMod.dll
114+ mv -f PolyMod.new.dll BepInEx/plugins/PolyMod.dll
115+
116+ echo ""Launching game...""
117+ xdg-open steam://rungameid/874390 &
118+
119+ sleep 3
120+ exit 0
121+ " ) ;
122+
123+ System . Diagnostics . Process chmod = new System . Diagnostics . Process ( ) ;
124+ chmod . StartInfo . FileName = "chmod" ;
125+ chmod . StartInfo . Arguments = $ "+x \" { bashPath } \" ";
126+ chmod . StartInfo . UseShellExecute = false ;
127+ chmod . StartInfo . CreateNoWindow = true ;
128+ chmod . Start ( ) ;
129+ chmod . WaitForExit ( ) ;
130+
131+ info . FileName = "/bin/bash" ;
132+ info . Arguments = $ "\" { bashPath } \" ";
133+ info . WorkingDirectory = Plugin . BASE_PATH ;
134+ info . CreateNoWindow = true ;
135+ info . UseShellExecute = false ;
136+ }
137+ Process . Start ( info ) ;
138+ Application . Quit ( ) ;
139+ }
140+ PopupManager . GetBasicPopup ( new (
141+ Localization . Get ( "polymod.autoupdate" ) ,
142+ Localization . Get ( "polymod.autoupdate.description" ) ,
143+ new ( new PopupBase . PopupButtonData [ ] {
144+ new (
145+ "polymod.autoupdate.update" ,
146+ PopupBase . PopupButtonData . States . None ,
147+ ( Il2CppSystem . Action ) Update
148+ )
149+ } ) )
150+ ) . Show ( ) ;
151+ }
152+ catch ( Exception e )
153+ {
154+ Plugin . logger . LogError ( $ "Failed to check updates: { e . Message } ") ;
155+ }
156+ }
157+
158+ internal static void Init ( )
159+ {
160+ Harmony . CreateAndPatchAll ( typeof ( AutoUpdate ) ) ;
161+ }
162+ }
0 commit comments