1616using System . Windows . Media . Imaging ;
1717using Windows . Gaming . Input ;
1818using Windows . Gaming . Preview . GamesEnumeration ;
19+ using YamlDotNet . Serialization . NamingConventions ;
20+ using YamlDotNet . Serialization ;
21+ using ImageMagick . Drawing ;
1922
2023namespace gamevault . Helper . Integrations
2124{
@@ -88,10 +91,11 @@ internal async Task<bool> RestoreBackup(int gameId, string installationDir)
8891 throw new Exception ( "no savegame extracted" ) ;
8992
9093 extractFolder = Path . GetDirectoryName ( Path . GetDirectoryName ( mappingFile [ 0 ] ) ) ;
94+ PrepareConfigFile ( installationDir , Path . Combine ( AppFilePath . CloudSaveConfigDir , "config.yaml" ) ) ;
9195 Process process = new Process ( ) ;
9296 ProcessShepherd . Instance . AddProcess ( process ) ;
9397 process . StartInfo = CreateProcessHeader ( ) ;
94- process . StartInfo . Arguments = $ "restore --force --path \" { extractFolder } \" ";
98+ process . StartInfo . Arguments = $ "--config { AppFilePath . CloudSaveConfigDir } restore --force --path \" { extractFolder } \" ";
9599 process . Start ( ) ;
96100 process . WaitForExit ( ) ;
97101 ProcessShepherd . Instance . RemoveProcess ( process ) ;
@@ -172,7 +176,12 @@ internal async Task<bool> BackupSaveGame(int gameId)
172176 if ( gameMetadataTitle != "" && installationDir != "" )
173177 {
174178 string title = await SearchForLudusaviGameTitle ( gameMetadataTitle ) ;
175- string tempFolder = await CreateBackup ( title ) ;
179+ if ( string . IsNullOrEmpty ( title ) )
180+ return false ;
181+ string tempFolder = Path . Combine ( Path . GetTempPath ( ) , Guid . NewGuid ( ) . ToString ( ) ) ;
182+ Directory . CreateDirectory ( tempFolder ) ;
183+ PrepareConfigFile ( installedGame ? . Value ! , Path . Combine ( AppFilePath . CloudSaveConfigDir , "config.yaml" ) ) ;
184+ await CreateBackup ( title , tempFolder ) ;
176185 string archive = Path . Combine ( tempFolder , "backup.zip" ) ;
177186 if ( Directory . GetFiles ( tempFolder , "mapping.yaml" , SearchOption . AllDirectories ) . Length == 0 )
178187 {
@@ -187,6 +196,69 @@ internal async Task<bool> BackupSaveGame(int gameId)
187196 }
188197 return false ;
189198 }
199+ public void PrepareConfigFile ( string installationPath , string yamlPath )
200+ {
201+ string userFolder = Environment . GetFolderPath ( Environment . SpecialFolder . UserProfile ) ;
202+ var redirects = new Dictionary < string , object >
203+ {
204+ { "redirects" , new List < Dictionary < string , object > >
205+ {
206+ new Dictionary < string , object >
207+ {
208+ { "kind" , "bidirectional" } ,
209+ { "source" , userFolder } ,
210+ { "target" , "G:\\ gamevault\\ currentuser" }
211+ } ,
212+ new Dictionary < string , object >
213+ {
214+ { "kind" , "bidirectional" } ,
215+ { "source" , installationPath } ,
216+ { "target" , "G:\\ gamevault\\ installation" }
217+ }
218+ }
219+ }
220+ } ;
221+
222+ // Simulating SettingsViewModel.Instance.CustomCloudSaveManifests
223+ var customLudusaviManifests = SettingsViewModel . Instance . CustomCloudSaveManifests . Where ( m => ! string . IsNullOrWhiteSpace ( m . Uri ) ) ;
224+
225+ Dictionary < string , object > yamlData ;
226+
227+ if ( customLudusaviManifests . Any ( ) ) // If manifests exist, merge with redirects
228+ {
229+ var manifest = new Dictionary < string , object >
230+ {
231+ { "enable" , SettingsViewModel . Instance . UsePrimaryCloudSaveManifest } ,
232+ { "secondary" , new List < Dictionary < string , object > > ( ) }
233+ } ;
234+
235+ foreach ( LudusaviManifestEntry entry in customLudusaviManifests )
236+ {
237+ ( ( List < Dictionary < string , object > > ) manifest [ "secondary" ] ) . Add ( new Dictionary < string , object >
238+ {
239+ { Uri . IsWellFormedUriString ( entry . Uri , UriKind . Absolute ) ? "url" : "path" , entry . Uri } ,
240+ { "enable" , true }
241+ } ) ;
242+ }
243+
244+ yamlData = new Dictionary < string , object >
245+ {
246+ { "manifest" , manifest } ,
247+ { "redirects" , redirects [ "redirects" ] } // Merge redirects
248+ } ;
249+ }
250+ else
251+ {
252+ yamlData = redirects ; // Only redirects if no manifests
253+ }
254+
255+ var serializer = new SerializerBuilder ( )
256+ . WithNamingConvention ( UnderscoredNamingConvention . Instance )
257+ . Build ( ) ;
258+
259+ string result = serializer . Serialize ( yamlData ) ;
260+ File . WriteAllText ( yamlPath , result ) ;
261+ }
190262 internal async Task < string > SearchForLudusaviGameTitle ( string title )
191263 {
192264 return await Task . Run < string > ( ( ) =>
@@ -223,21 +295,19 @@ internal async Task<string> SearchForLudusaviGameTitle(string title)
223295 return "" ;
224296 } ) ;
225297 }
226- private async Task < string > CreateBackup ( string lunusaviTitle )
298+ private async Task CreateBackup ( string lunusaviTitle , string tempFolder )
227299 {
228- return await Task . Run < string > ( ( ) =>
229- {
230- string tempFolder = Path . Combine ( Path . GetTempPath ( ) , Guid . NewGuid ( ) . ToString ( ) ) ;
300+ await Task . Run ( ( ) =>
301+ {
302+ Process process = new Process ( ) ;
303+ ProcessShepherd . Instance . AddProcess ( process ) ;
304+ process . StartInfo = CreateProcessHeader ( ) ;
305+ process . StartInfo . Arguments = $ "--config { AppFilePath . CloudSaveConfigDir } backup --force --format \" zip\" --path \" { tempFolder } \" \" { lunusaviTitle } \" ";
306+ process . Start ( ) ;
307+ process . WaitForExit ( ) ;
308+ ProcessShepherd . Instance . RemoveProcess ( process ) ;
231309
232- Process process = new Process ( ) ;
233- ProcessShepherd . Instance . AddProcess ( process ) ;
234- process . StartInfo = CreateProcessHeader ( ) ;
235- process . StartInfo . Arguments = $ "backup --force --format \" zip\" --path \" { tempFolder } \" \" { lunusaviTitle } \" ";
236- process . Start ( ) ;
237- process . WaitForExit ( ) ;
238- ProcessShepherd . Instance . RemoveProcess ( process ) ;
239- return tempFolder ;
240- } ) ;
310+ } ) ;
241311 }
242312 private async Task < bool > UploadSavegame ( string saveFilePath , int gameId , string installationDir )
243313 {
@@ -279,4 +349,8 @@ private ProcessStartInfo CreateProcessHeader(bool redirectConsole = false)
279349 return info ;
280350 }
281351 }
352+ public class LudusaviManifestEntry
353+ {
354+ public string Uri { get ; set ; }
355+ }
282356}
0 commit comments