Пример #1
0
        /// <summary>
        /// Purges the mod directory asynchronous.
        /// </summary>
        /// <param name="parameters">The parameters.</param>
        /// <param name="deleteAll">if set to <c>true</c> [delete all].</param>
        /// <returns>Task&lt;System.Boolean&gt;.</returns>
        public Task <bool> PurgeModDirectoryAsync(ModWriterParameters parameters, bool deleteAll = false)
        {
            var fullPath = Path.Combine(parameters.RootDirectory ?? string.Empty, parameters.Path ?? string.Empty);

            if (Directory.Exists(fullPath))
            {
                if (!deleteAll)
                {
                    var files = Directory.EnumerateFiles(fullPath, "*", SearchOption.TopDirectoryOnly);
                    foreach (var item in files)
                    {
                        File.Delete(item);
                    }
                }
                else
                {
                    Directory.Delete(fullPath, true);
                }
                return(Task.FromResult(true));
            }
            else if (File.Exists(fullPath))
            {
                File.Delete(fullPath);
                return(Task.FromResult(true));
            }
            return(Task.FromResult(false));
        }
Пример #2
0
        /// <summary>
        /// Ensures the database exists.
        /// </summary>
        /// <param name="parameters">The parameters.</param>
        private void EnsureDbExists(ModWriterParameters parameters)
        {
            var db = GetDbPath(parameters);

            if (!File.Exists(db))
            {
                File.Copy(Constants.Empty_sql_db_path, db);
            }
        }
Пример #3
0
        /// <summary>
        /// export as an asynchronous operation.
        /// </summary>
        /// <param name="parameters">The parameters.</param>
        /// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns>
        public async Task <bool> ExportAsync(ModWriterParameters parameters)
        {
            EnsureDbExists(parameters);
            var collection = await RecreateCollectionAsync(parameters);

            await SyncModsAsync(collection, parameters);

            return(true);
        }
Пример #4
0
        /// <summary>
        /// Mods the directory exists asynchronous.
        /// </summary>
        /// <param name="parameters">The parameters.</param>
        /// <returns>Task&lt;System.Boolean&gt;.</returns>
        public virtual Task <bool> ModDirectoryExistsAsync(ModWriterParameters parameters)
        {
            var fullPath = Path.Combine(parameters.RootDirectory, parameters.Path);

            if (!Directory.Exists(fullPath))
            {
                return(Task.FromResult(false));
            }
            return(Task.FromResult(Directory.EnumerateFileSystemEntries(fullPath).Any()));
        }
Пример #5
0
        /// <summary>
        /// Descriptors the exists asynchronous.
        /// </summary>
        /// <param name="parameters">The parameters.</param>
        /// <returns>Task&lt;System.Boolean&gt;.</returns>
        public Task <bool> DescriptorExistsAsync(ModWriterParameters parameters)
        {
            var fullPath = Path.Combine(parameters.RootDirectory, parameters.Mod.DescriptorFile);

            if (File.Exists(fullPath))
            {
                return(Task.FromResult(true));
            }
            return(Task.FromResult(false));
        }
Пример #6
0
        /// <summary>
        /// Exports the mods asynchronous.
        /// </summary>
        /// <param name="enabledMods">The mods.</param>
        /// <param name="regularMods">The regular mods.</param>
        /// <param name="modCollection">The mod collection.</param>
        /// <returns>Task&lt;System.Boolean&gt;.</returns>
        public virtual async Task <bool> ExportModsAsync(IReadOnlyCollection <IMod> enabledMods, IReadOnlyCollection <IMod> regularMods, IModCollection modCollection)
        {
            var game = GameService.GetSelected();

            if (game == null || enabledMods == null || regularMods == null || modCollection == null)
            {
                return(false);
            }
            var allMods        = GetInstalledModsInternal(game, false);
            var mod            = GeneratePatchModDescriptor(allMods, game, GenerateCollectionPatchName(modCollection.Name));
            var applyModParams = new ModWriterParameters()
            {
                OtherMods     = regularMods.Where(p => !enabledMods.Any(m => m.DescriptorFile.Equals(p.DescriptorFile))).ToList(),
                EnabledMods   = enabledMods,
                RootDirectory = game.UserDirectory
            };

            if (await ModWriter.ModDirectoryExistsAsync(new ModWriterParameters()
            {
                RootDirectory = mod.FullPath
            }))
            {
                if (modCollection.PatchModEnabled && enabledMods.Any())
                {
                    if (await ModWriter.WriteDescriptorAsync(new ModWriterParameters()
                    {
                        Mod = mod,
                        RootDirectory = game.UserDirectory,
                        Path = mod.DescriptorFile,
                        LockDescriptor = CheckIfModShouldBeLocked(game, mod)
                    }, IsPatchModInternal(mod)))
                    {
                        applyModParams.TopPriorityMods = new List <IMod>()
                        {
                            mod
                        };
                        Cache.Invalidate(new CacheInvalidateParameters()
                        {
                            Region = ModsCacheRegion, Prefix = game.Type, Keys = new List <string> {
                                GetModsCacheKey(true), GetModsCacheKey(false)
                            }
                        });
                    }
                }
            }
            else
            {
                // Remove left over descriptor
                if (allMods.Any(p => p.Name.Equals(mod.Name)))
                {
                    await DeleteDescriptorsInternalAsync(new List <IMod>() { mod });
                }
            }
            return(await ModWriter.ApplyModsAsync(applyModParams));
        }
Пример #7
0
        /// <summary>
        /// Creates the mod directory asynchronous.
        /// </summary>
        /// <param name="parameters">The parameters.</param>
        /// <returns>Task&lt;System.Boolean&gt;.</returns>
        public Task <bool> CreateModDirectoryAsync(ModWriterParameters parameters)
        {
            var fullPath = Path.Combine(parameters.RootDirectory, parameters.Path);

            if (!Directory.Exists(fullPath))
            {
                Directory.CreateDirectory(fullPath);
                return(Task.FromResult(true));
            }
            return(Task.FromResult(false));
        }
Пример #8
0
        /// <summary>
        /// write descriptor as an asynchronous operation.
        /// </summary>
        /// <param name="parameters">The parameters.</param>
        /// <param name="writeDescriptorInModDirectory">if set to <c>true</c> [write descriptor in mod directory].</param>
        /// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns>
        public async Task <bool> WriteDescriptorAsync(ModWriterParameters parameters, bool writeDescriptorInModDirectory)
        {
            async Task <bool> writeDescriptors()
            {
                // If needed I've got a much more complex serializer, it is written for Kerbal Space Program but the structure seems to be the same though this is much more simpler
                var fullPath = Path.Combine(parameters.RootDirectory ?? string.Empty, parameters.Path ?? string.Empty);

                await writeDescriptor(fullPath);

                // Attempt to fix issues where the game decides to delete local zipped mod descriptors (I'm assuming this happens to all pdx games)
                if (parameters.LockDescriptor)
                {
                    if (File.Exists(fullPath))
                    {
                        _ = new System.IO.FileInfo(fullPath)
                        {
                            IsReadOnly = true
                        };
                    }
                }
                if (writeDescriptorInModDirectory)
                {
                    var modPath = Path.Combine(parameters.Mod.FileName, Shared.Constants.DescriptorFile);
                    await writeDescriptor(modPath);
                }
                return(true);
            }

            async Task <bool> writeDescriptor(string fullPath)
            {
                bool?state = null;

                if (File.Exists(fullPath))
                {
                    var fileInfo = new System.IO.FileInfo(fullPath);
                    state = fileInfo.IsReadOnly;
                    fileInfo.IsReadOnly = false;
                }
                using var fs = new FileStream(fullPath, FileMode.Create, FileAccess.Write, FileShare.Read);
                var result = await WriteDescriptorToStreamAsync(parameters, fs);

                if (state.HasValue)
                {
                    var fileInfo = new System.IO.FileInfo(fullPath);
                    fileInfo.IsReadOnly = state.GetValueOrDefault();
                }
                return(result);
            }

            var retry = new RetryStrategy();

            return(await retry.RetryActionAsync(writeDescriptors));
        }
Пример #9
0
        /// <summary>
        /// write descriptor to stream as an asynchronous operation.
        /// </summary>
        /// <param name="parameters">The parameters.</param>
        /// <param name="stream">The stream.</param>
        /// <returns>Task&lt;System.Boolean&gt;.</returns>
        public async Task <bool> WriteDescriptorToStreamAsync(ModWriterParameters parameters, Stream stream)
        {
            using var sw = new StreamWriter(stream, leaveOpen: true);
            var props = parameters.Mod.GetType().GetProperties().Where(p => Attribute.IsDefined(p, typeof(DescriptorPropertyAttribute)));

            foreach (var prop in props)
            {
                var attr = Attribute.GetCustomAttribute(prop, typeof(DescriptorPropertyAttribute), true) as DescriptorPropertyAttribute;
                var val  = prop.GetValue(parameters.Mod, null);
                if (val is IEnumerable <string> col)
                {
                    if (col.Any())
                    {
                        if (attr.KeyedArray)
                        {
                            foreach (var item in col)
                            {
                                await sw.WriteLineAsync($"{attr.PropertyName}=\"{item}\"");
                            }
                        }
                        else
                        {
                            await sw.WriteLineAsync($"{attr.PropertyName}={{");

                            foreach (var item in col)
                            {
                                await sw.WriteLineAsync($"\t\"{item}\"");
                            }
                            await sw.WriteLineAsync("}");
                        }
                    }
                }
                else
                {
                    if (!string.IsNullOrWhiteSpace(val != null ? val.ToString() : string.Empty))
                    {
                        if (attr.AlternateNameEndsWithCondition?.Count() > 0 && attr.AlternateNameEndsWithCondition.Any(p => val.ToString().EndsWith(p, StringComparison.OrdinalIgnoreCase)))
                        {
                            await sw.WriteLineAsync($"{attr.AlternatePropertyName}=\"{val}\"");
                        }
                        else
                        {
                            await sw.WriteLineAsync($"{attr.PropertyName}=\"{val}\"");
                        }
                    }
                }
            }
            await sw.FlushAsync();

            return(true);
        }
Пример #10
0
        /// <summary>
        /// Sets the descriptor lock asynchronous.
        /// </summary>
        /// <param name="parameters">The parameters.</param>
        /// <param name="isLocked">if set to <c>true</c> [is locked].</param>
        /// <returns>Task&lt;System.Boolean&gt;.</returns>
        public Task <bool> SetDescriptorLockAsync(ModWriterParameters parameters, bool isLocked)
        {
            var fullPath = Path.Combine(parameters.RootDirectory, parameters.Mod.DescriptorFile);

            if (File.Exists(fullPath))
            {
                _ = new System.IO.FileInfo(fullPath)
                {
                    IsReadOnly = isLocked
                };
                return(Task.FromResult(true));
            }
            return(Task.FromResult(false));
        }
Пример #11
0
        /// <summary>
        /// Deletes the descriptor asynchronous.
        /// </summary>
        /// <param name="parameters">The parameters.</param>
        /// <returns>Task&lt;System.Boolean&gt;.</returns>
        public Task <bool> DeleteDescriptorAsync(ModWriterParameters parameters)
        {
            var fullPath = Path.Combine(parameters.RootDirectory, parameters.Mod.DescriptorFile);

            if (File.Exists(fullPath))
            {
                _ = new System.IO.FileInfo(fullPath)
                {
                    IsReadOnly = false
                };
                File.Delete(fullPath);
                return(Task.FromResult(true));
            }
            return(Task.FromResult(false));
        }
Пример #12
0
        /// <summary>
        /// apply mods as an asynchronous operation.
        /// </summary>
        /// <param name="parameters">The parameters.</param>
        /// <returns>Task&lt;System.Boolean&gt;.</returns>
        public async Task <bool> ApplyModsAsync(ModWriterParameters parameters)
        {
            Task <bool>[] tasks;
            using (var mutex = await writeLock.LockAsync())
            {
                tasks = new Task <bool>[]
                {
                    Task.Run(async() => await sqliteExporter.ExportAsync(parameters)),
                    Task.Run(async() => await jsonExporter.ExportAsync(parameters))
                };
                await Task.WhenAll(tasks);
            }

            return(tasks.All(p => p.Result));
        }
Пример #13
0
        /// <summary>
        /// Gets the patch mod directory.
        /// </summary>
        /// <param name="game">The game.</param>
        /// <param name="patchOrMergeName">Name of the patch or merge.</param>
        /// <returns>System.String.</returns>
        protected virtual string GetPatchModDirectory(IGame game, string patchOrMergeName)
        {
            var path = Path.Combine(game.UserDirectory, Shared.Constants.ModDirectory, patchOrMergeName);

            path = path.StandardizeDirectorySeparator();
            var parameters = new ModWriterParameters()
            {
                Path = path
            };

            if (!ModWriter.ModDirectoryExists(parameters) && !string.IsNullOrWhiteSpace(game.CustomModDirectory))
            {
                path = Path.Combine(game.CustomModDirectory, patchOrMergeName).StandardizeDirectorySeparator();
            }
            return(path);
        }
Пример #14
0
        /// <summary>
        /// Exports the mods asynchronous.
        /// </summary>
        /// <param name="enabledMods">The mods.</param>
        /// <param name="regularMods">The regular mods.</param>
        /// <param name="collectionName">Name of the collection.</param>
        /// <returns>Task&lt;System.Boolean&gt;.</returns>
        public virtual async Task <bool> ExportModsAsync(IReadOnlyCollection <IMod> enabledMods, IReadOnlyCollection <IMod> regularMods, string collectionName)
        {
            var game = GameService.GetSelected();

            if (game == null || enabledMods == null || regularMods == null)
            {
                return(false);
            }
            var allMods        = GetInstalledModsInternal(game, false);
            var mod            = GeneratePatchModDescriptor(allMods, game, GenerateCollectionPatchName(collectionName));
            var applyModParams = new ModWriterParameters()
            {
                OtherMods     = regularMods.Where(p => !enabledMods.Any(m => m.DescriptorFile.Equals(p.DescriptorFile))).ToList(),
                EnabledMods   = enabledMods,
                RootDirectory = game.UserDirectory
            };

            if (await ModWriter.ModDirectoryExistsAsync(new ModWriterParameters()
            {
                RootDirectory = game.UserDirectory,
                Path = mod.FileName
            }))
            {
                if (await ModWriter.WriteDescriptorAsync(new ModWriterParameters()
                {
                    Mod = mod,
                    RootDirectory = game.UserDirectory,
                    Path = mod.DescriptorFile
                }, IsPatchModInternal(mod)))
                {
                    applyModParams.TopPriorityMods = new List <IMod>()
                    {
                        mod
                    };
                    Cache.Invalidate(ModsCachePrefix, ConstructModsCacheKey(game, true), ConstructModsCacheKey(game, false));
                }
            }
            return(await ModWriter.ApplyModsAsync(applyModParams));
        }
Пример #15
0
        /// <summary>
        /// export as an asynchronous operation.
        /// </summary>
        /// <param name="parameters">The parameters.</param>
        /// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns>
        public async Task <bool> ExportAsync(ModWriterParameters parameters)
        {
            var dlcPath         = Path.Combine(parameters.RootDirectory, Constants.DLC_load_path);
            var gameDataPath    = Path.Combine(parameters.RootDirectory, Constants.Game_data_path);
            var modRegistryPath = Path.Combine(parameters.RootDirectory, Constants.Mod_registry_path);
            var dLCLoad         = await LoadPdxModelAsync <DLCLoad>(dlcPath) ?? new DLCLoad();

            var gameData = await LoadPdxModelAsync <GameData>(gameDataPath) ?? new GameData();

            var modRegistry = await LoadPdxModelAsync <ModRegistryCollection>(modRegistryPath) ?? new ModRegistryCollection();

            if (!parameters.AppendOnly)
            {
                gameData.ModsOrder.Clear();
                dLCLoad.EnabledMods.Clear();
            }

            // Remove invalid mods
            var toRemove = new List <string>();

            foreach (var pdxMod in modRegistry)
            {
                if (pdxMod.Value.Status != Constants.Ready_to_play)
                {
                    toRemove.Add(pdxMod.Key);
                }
            }
            foreach (var item in toRemove)
            {
                modRegistry.Remove(item);
            }

            if (parameters.EnabledMods != null)
            {
                foreach (var mod in parameters.EnabledMods)
                {
                    SyncData(dLCLoad, gameData, modRegistry, mod, true);
                }
            }

            if (parameters.OtherMods != null)
            {
                foreach (var mod in parameters.OtherMods)
                {
                    SyncData(dLCLoad, gameData, modRegistry, mod, false);
                }
            }

            if (parameters.TopPriorityMods != null)
            {
                foreach (var mod in parameters.TopPriorityMods)
                {
                    var existingEntry = modRegistry.Values.FirstOrDefault(p => p.GameRegistryId.Equals(mod.DescriptorFile, StringComparison.OrdinalIgnoreCase));
                    if (existingEntry != null)
                    {
                        gameData.ModsOrder.Remove(existingEntry.Id);
                    }
                    var existingEnabledMod = dLCLoad.EnabledMods.FirstOrDefault(p => p.Equals(mod.DescriptorFile, StringComparison.OrdinalIgnoreCase));
                    if (!string.IsNullOrWhiteSpace(existingEnabledMod))
                    {
                        dLCLoad.EnabledMods.Remove(existingEnabledMod);
                    }
                    SyncData(dLCLoad, gameData, modRegistry, mod, true);
                }
            }

            var tasks = new Task <bool>[]
            {
                WritePdxModelAsync(dLCLoad, dlcPath),
                WritePdxModelAsync(gameData, gameDataPath),
                WritePdxModelAsync(modRegistry, modRegistryPath),
            };
            await Task.WhenAll(tasks);

            return(tasks.All(p => p.Result));
        }
Пример #16
0
        /// <summary>
        /// write descriptor as an asynchronous operation.
        /// </summary>
        /// <param name="parameters">The parameters.</param>
        /// <param name="writeDescriptorInModDirectory">if set to <c>true</c> [write descriptor in mod directory].</param>
        /// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns>
        public async Task <bool> WriteDescriptorAsync(ModWriterParameters parameters, bool writeDescriptorInModDirectory)
        {
            async Task <bool> writeDescriptors()
            {
                // If needed I've got a much more complex serializer, it is written for Kerbal Space Program but the structure seems to be the same though this is much more simpler
                var fullPath = Path.Combine(parameters.RootDirectory ?? string.Empty, parameters.Path ?? string.Empty);

                await writeDescriptor(fullPath);

                if (writeDescriptorInModDirectory)
                {
                    var modPath = Path.Combine(parameters.Mod.FileName, Shared.Constants.DescriptorFile);
                    await writeDescriptor(modPath);
                }
                return(true);
            }

            async Task <bool> writeDescriptor(string fullPath)
            {
                using var fs = new FileStream(fullPath, FileMode.Create, FileAccess.Write, FileShare.Read);
                using var sw = new StreamWriter(fs);
                var props = parameters.Mod.GetType().GetProperties().Where(p => Attribute.IsDefined(p, typeof(DescriptorPropertyAttribute)));

                foreach (var prop in props)
                {
                    var attr = Attribute.GetCustomAttribute(prop, typeof(DescriptorPropertyAttribute), true) as DescriptorPropertyAttribute;
                    var val  = prop.GetValue(parameters.Mod, null);
                    if (val is IEnumerable <string> col)
                    {
                        if (col.Count() > 0)
                        {
                            await sw.WriteLineAsync($"{attr.PropertyName}={{");

                            foreach (var item in col)
                            {
                                await sw.WriteLineAsync($"\t\"{item}\"");
                            }
                            await sw.WriteLineAsync("}");
                        }
                    }
                    else
                    {
                        if (!string.IsNullOrWhiteSpace(val != null ? val.ToString() : string.Empty))
                        {
                            if (attr.AlternateNameEndsWithCondition?.Count() > 0 && attr.AlternateNameEndsWithCondition.Any(p => val.ToString().EndsWith(p, StringComparison.OrdinalIgnoreCase)))
                            {
                                await sw.WriteLineAsync($"{attr.AlternatePropertyName}=\"{val}\"");
                            }
                            else
                            {
                                await sw.WriteLineAsync($"{attr.PropertyName}=\"{val}\"");
                            }
                        }
                    }
                }
                await sw.FlushAsync();

                return(true);
            }

            var retry = new RetryStrategy();

            return(await retry.RetryActionAsync(writeDescriptors));
        }
Пример #17
0
 /// <summary>
 /// Gets the connection.
 /// </summary>
 /// <param name="parameters">The parameters.</param>
 /// <returns>IDbConnection.</returns>
 private IDbConnection GetConnection(ModWriterParameters parameters)
 {
     return(new SqliteConnection($"Data Source=\"{GetDbPath(parameters)}\"").EnsureOpen());
 }
Пример #18
0
 /// <summary>
 /// Gets the database path.
 /// </summary>
 /// <param name="parameters">The parameters.</param>
 /// <returns>System.String.</returns>
 private string GetDbPath(ModWriterParameters parameters)
 {
     return(Path.Combine(parameters.RootDirectory, Constants.Sql_db_path));
 }
Пример #19
0
        /// <summary>
        /// recreate collection as an asynchronous operation.
        /// </summary>
        /// <param name="parameters">The parameters.</param>
        /// <returns>Playsets.</returns>
        private async Task <Playsets> RecreateCollectionAsync(ModWriterParameters parameters)
        {
            Playsets getDefaultIronyCollection()
            {
                return(new Playsets()
                {
                    Id = Guid.NewGuid().ToString(),
                    IsActive = true,
                    LoadOrder = CollectionSortType,
                    Name = GetCollectionName()
                });
            }

            var colName = GetCollectionName();

            // They did do a cascade delete right?
            using var con         = GetConnection(parameters);
            using var transaction = con.BeginTransaction();

            var activeCollections = (await con.QueryAsync <Playsets>(p => p.IsActive == true, trace: trace)).ToList().Where(p => !p.Name.Equals(colName)).ToList();

            try
            {
                Playsets ironyCollection;
                if (!parameters.AppendOnly)
                {
                    await con.DeleteAsync <Playsets>(p => p.Name == colName, transaction : transaction, trace : trace);

                    if (activeCollections.Count() > 0)
                    {
                        foreach (var item in activeCollections)
                        {
                            item.IsActive = false;
                        }
                        await con.UpdateAllAsync(activeCollections, transaction : transaction, trace : trace);
                    }

                    ironyCollection = getDefaultIronyCollection();
                    await con.InsertAsync(ironyCollection, transaction : transaction, trace : trace);
                }
                else
                {
                    ironyCollection = (await con.QueryAsync <Playsets>(p => p.Name == colName, trace: trace)).FirstOrDefault();

                    if (activeCollections.Count() > 0)
                    {
                        foreach (var item in activeCollections)
                        {
                            item.IsActive = false;
                        }
                        await con.UpdateAllAsync(activeCollections, transaction : transaction, trace : trace);
                    }

                    if (ironyCollection == null)
                    {
                        ironyCollection = getDefaultIronyCollection();
                        await con.InsertAsync(ironyCollection, transaction : transaction, trace : trace);
                    }
                    else
                    {
                        ironyCollection.IsActive = true;
                        await con.UpdateAsync(ironyCollection, transaction : transaction, trace : trace);
                    }
                }

                transaction.Commit();

                return(ironyCollection);
            }
            catch (Exception ex)
            {
                logger.Error(ex);
                transaction.Rollback();
                throw;
            }
        }