public ResolverManagerModResultPair(IModResolver resolver, IUpdateManager manager, CheckForUpdatesResult result, PathTuple <ModConfig> modTuple) { Resolver = resolver; Manager = manager; Result = result; ModTuple = modTuple; }
/// <summary> /// Applies an individual application item to a given application configuration. /// </summary> /// <param name="indexApp">Index entry for the application.</param> /// <param name="pathTuple">The mod to apply the config to.</param> public static void ApplyIndexEntry(AppItem indexApp, PathTuple <ApplicationConfig> pathTuple) { using var fileStream = new FileStream(ApplicationConfig.GetAbsoluteAppLocation(pathTuple), FileMode.Open, FileAccess.Read, FileShare.ReadWrite, 524288); var hash = Hashing.ToString(xxHash64.ComputeHash(fileStream)); ApplyIndexEntry(indexApp, pathTuple, hash); }
/// <summary> /// Converts the relative or absolute application location to a full path. /// </summary> /// <returns>The full path to the app location.</returns> public static string GetAbsoluteAppLocation(PathTuple <ApplicationConfig> config) { var location = config.Config.AppLocation; var basePath = Path.GetDirectoryName(config.Path) !; string finalPath; // Specific for windows paths starting on \ - they need the drive added to them. // I constructed this piece like this for possible Mono support. if (!Path.IsPathRooted(location) || "\\".Equals(Path.GetPathRoot(location))) { if (location.StartsWith(Path.DirectorySeparatorChar)) { finalPath = Path.Combine(Path.GetPathRoot(basePath) !, location.TrimStart(Path.DirectorySeparatorChar)); } else { finalPath = Path.Combine(basePath, location); } } else { finalPath = location; } // Resolves any internal "..\" to get the true full path. return(Path.GetFullPath(finalPath)); }
public bool IsCompatible(PathTuple <ModConfig> mod) { var modDirectory = Path.GetDirectoryName(mod.Path); ConfigPath = GameBananaConfig.GetFilePath(modDirectory); return(File.Exists(ConfigPath)); }
/// <summary> /// Builds the initial set of mods to display in the list. /// </summary> private List <ModEntry> GetInitialModSet(ApplicationViewModel model, PathTuple <ApplicationConfig> applicationTuple) { // Note: Must put items in top to bottom load order. var enabledModIds = applicationTuple.Config.EnabledMods; var modsForThisApp = model.ModsForThisApp.ToArray(); // Get dictionary of mods for this app by Mod ID var modDictionary = new Dictionary <string, PathTuple <ModConfig> >(); foreach (var mod in modsForThisApp) { modDictionary[mod.Config.ModId] = mod; } // Add enabled mods. var totalModList = new List <ModEntry>(modsForThisApp.Length); foreach (var enabledModId in enabledModIds) { if (modDictionary.ContainsKey(enabledModId)) { totalModList.Add(MakeSaveSubscribedModEntry(true, modDictionary[enabledModId])); } } // Add disabled mods. var enabledModIdSet = applicationTuple.Config.EnabledMods.ToHashSet(); var disabledMods = modsForThisApp.Where(x => !enabledModIdSet.Contains(x.Config.ModId)); totalModList.AddRange(disabledMods.Select(x => MakeSaveSubscribedModEntry(false, x))); return(totalModList); }
public SetDependenciesDialogViewmodel(ModConfigService configService, PathTuple <ModConfig> modConfig) { ConfigService = configService; CurrentMod = modConfig; PopulateDependencies(); }
/// <summary> /// Returns the first appropriate provider that can handle fetching packages for a game. /// </summary> /// <param name="application">The application in question.</param> /// <param name="nugetRepositories">[Optional] NuGet repositories to use.</param> /// <returns>A resolver that can handle the mod, else null.</returns> public static AggregatePackageProvider?GetProvider(PathTuple <ApplicationConfig> application, IEnumerable <INugetRepository>?nugetRepositories = null) { // Create resolvers. var providers = new List <IDownloadablePackageProvider>(); foreach (var factory in All) { var provider = factory.GetProvider(application); if (provider != null) { providers.Add(provider); } } // Add NuGets. if (nugetRepositories != null) { foreach (var nugetRepo in nugetRepositories) { providers.Add(new IndexedNuGetPackageProvider(nugetRepo, application.Config.AppId)); } } return(providers.Count > 0 ? new AggregatePackageProvider(providers.ToArray(), application.Config.AppName) : null); }
/* Mod Loading */ /// <summary> /// Obtains an instance of an individual ready to load mod. /// To start an instance, call <see cref="StartMod"/> /// </summary> /// <exception cref="ArgumentException">Mod with specified ID is already loaded.</exception> /// <param name="tuple">A tuple of mod config and path to config.</param> private ModInstance GetModInstance(PathTuple <ModConfig> tuple) { // Check if mod with ID already loaded. if (IsModLoaded(tuple.Config.ModId)) { throw new ReloadedException(Errors.ModAlreadyLoaded(tuple.Config.ModId)); } // Load DLL or non-dll mod. if (tuple.Config.HasDllPath()) { var dllPath = tuple.Config.GetDllPath(tuple.Path); if (File.Exists(dllPath)) { return(tuple.Config.IsNativeMod(tuple.Path) ? PrepareNativeMod(tuple) : PrepareDllMod(tuple)); } else { _loader?.Logger?.WriteLineAsync(AddLogPrefix($"DLL Not Found! {Path.GetFileName(dllPath)}\n" + $"Mod Name: {tuple.Config.ModName}, Mod ID: {tuple.Config.ModId}\n" + $"Please re-download the mod. It is either corrupt or you may have downloaded the source code by accident."), _loader.Logger.ColorRed); } } return(PrepareNonDllMod(tuple)); }
/// <summary> /// Returns the first appropriate resolver that can handle updating a mod. /// </summary> /// <param name="mod">The mod in question.</param> /// <param name="userConfig">Contains user configuration for this mod in question.</param> /// <param name="data">All data passed to the updater.</param> /// <returns>A resolver that can handle the mod, else null.</returns> public static AggregatePackageResolverEx?GetResolver(PathTuple <ModConfig> mod, PathTuple <ModUserConfig>?userConfig, UpdaterData data) { // Migrate first foreach (var factory in All) { factory.Migrate(mod, userConfig); } // Clone data preferences. data = data.DeepClone(); if (userConfig?.Config.AllowPrereleases != null) { data.CommonPackageResolverSettings.AllowPrereleases = userConfig.Config.AllowPrereleases.Value; } data.CommonPackageResolverSettings.MetadataFileName = mod.Config.ReleaseMetadataFileName; // Create resolvers. var resolvers = new List <IPackageResolver>(); var extractors = new Dictionary <IPackageResolver, IPackageExtractor>(); foreach (var factory in All) { var resolver = factory.GetResolver(mod, userConfig, data); if (resolver != null) { resolvers.Add(resolver); extractors[resolver] = factory.Extractor; } } return(resolvers.Count > 0 ? new AggregatePackageResolverEx(resolvers, extractors) : null); }
/// <summary> /// Applies an individual application item to a given application configuration. /// </summary> /// <param name="indexApp">Index entry for the application.</param> /// <param name="pathTuple">The mod to apply the config to.</param> /// <param name="hash">Hash of the application's main executable.</param> public static void ApplyIndexEntry(AppItem indexApp, PathTuple <ApplicationConfig> pathTuple, string hash) { var hashMatches = hash.Equals(indexApp.Hash, StringComparison.OrdinalIgnoreCase); if (indexApp.AppStatus == Status.WrongExecutable && hashMatches) { Actions.DisplayMessagebox(Resources.AddAppRepoBadExecutable.Get(), indexApp.BadStatusDescription !); } pathTuple.Config.AppName = indexApp.AppName; // Apply GB Configurations Singleton <GameBananaPackageProviderFactory> .Instance.SetConfiguration(pathTuple, new GameBananaPackageProviderFactory.GameBananaProviderConfig() { GameId = (int)indexApp.GameBananaId }); if (!hashMatches) { var viewModel = new AddAppHashMismatchDialogViewModel(indexApp.BadHashDescription !); Actions.ShowAddAppHashMismatchDialog(viewModel); } var appLocation = ApplicationConfig.GetAbsoluteAppLocation(pathTuple); if (indexApp.TryGetError(Path.GetDirectoryName(appLocation) !, out var errors)) { var viewModel = new AddApplicationWarningDialogViewModel(errors); Actions.ShowApplicationWarningDialog(viewModel); } }
/// <inheritdoc /> public bool TryGetConfigurationOrDefault(PathTuple <ApplicationConfig> mod, out object configuration) { var result = this.TryGetConfiguration <GameBananaProviderConfig>(mod, out var config); configuration = config ?? new GameBananaProviderConfig(); return(result); }
private void RemoveItem(PathTuple <TConfigType> itemTuple) { ItemsByPath.Remove(itemTuple.Path); ItemsByFolder.Remove(Path.GetDirectoryName(itemTuple.Path)); Items.Remove(itemTuple); OnRemoveItem?.Invoke(itemTuple); }
/// <summary> /// Obtains an image to represent a given application. /// The image is either a custom one or the icon of the application. /// </summary> private ImageSource GetImageForAppConfig(PathTuple <ApplicationConfig> applicationConfig) { // Check if custom icon exists. if (!string.IsNullOrEmpty(applicationConfig.Config.AppIcon)) { if (ApplicationConfig.TryGetApplicationIcon(applicationConfig.Path, applicationConfig.Config, out var applicationIcon)) { return(Misc.Imaging.BitmapFromUri(new Uri(applicationIcon, UriKind.Absolute))); } } // Otherwise extract new icon from executable. var appLocation = ApplicationConfig.GetAbsoluteAppLocation(applicationConfig); if (File.Exists(appLocation)) { // Else make new from icon. using Icon? ico = Icon.ExtractAssociatedIcon(appLocation); if (ico != null) { // Extract to config set location. BitmapSource bitmapImage = Imaging.CreateBitmapSourceFromHIcon(ico.Handle, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions()); bitmapImage.Freeze(); return(bitmapImage); } } return(Misc.Imaging.GetPlaceholderIcon()); }
private DateTime GetApproximateDateForMod(PathTuple <ModConfig> mod) { try { // Check date on the DLL if (mod.Config.HasDllPath()) { var dllPath = mod.Config.GetDllPath(mod.Path); if (!File.Exists(dllPath)) { goto checkIcon; } return(File.GetLastWriteTimeUtc(dllPath)); } // Otherwise fallback to icon, if possible. checkIcon: return(!mod.Config.TryGetIconPath(mod.Path, out var iconPath) ? DateTime.UtcNow : File.GetLastWriteTimeUtc(iconPath)); } catch (Exception) { return(DateTime.UtcNow); } }
/// <inheritdoc /> public bool TryGetConfigurationOrDefault(PathTuple <ModConfig> mod, out object configuration) { var result = this.TryGetConfiguration <NuGetConfig>(mod, out var config); configuration = config ?? new NuGetConfig(); return(result); }
private ModEntry MakeSaveSubscribedModEntry(bool?isEnabled, PathTuple <ModConfig> item) { // Make BooleanGenericTuple that saves application on Enabled change. var tuple = new ModEntry(isEnabled, item); tuple.PropertyChanged += SaveOnEnabledPropertyChanged; return(tuple); }
private ModInstance PrepareNativeMod(PathTuple <ModConfig> tuple) { var modId = tuple.Config.ModId; var dllPath = tuple.Config.GetNativeDllPath(tuple.Path); _modIdToFolder[modId] = Path.GetFullPath(Path.GetDirectoryName(tuple.Path)); return(new ModInstance(new NativeMod(dllPath), tuple.Config)); }
/// <inheritdoc /> public IDownloadablePackageProvider?GetProvider(PathTuple <ApplicationConfig> mod) { if (!this.TryGetConfiguration <GameBananaProviderConfig>(mod, out var gbConfig)) { return(null); } return(new IndexedGameBananaPackageProvider(gbConfig !.GameId)); }
public void Construct(PathTuple <ModConfig> mod) { _modTuple = mod; string path = GitHubConfig.GetFilePath(GetModDirectory(mod)); _githubConfig = IConfig <GitHubConfig> .FromPath(path); _githubUserConfig = IConfig <GitHubUserConfig> .FromPath(path); }
/// <summary> /// Saves a given mod tuple to the hard disk. /// </summary> public void SaveMod(PathTuple <ModConfig>?oldModTuple) { if (oldModTuple == null) { return; } oldModTuple.Config.SupportedAppId = EnabledAppIds.Where(x => x.Enabled).Select(x => x.Generic.AppId).ToArray(); oldModTuple.SaveAsync(); }
/// <inheritdoc/> public IPackageResolver?GetResolver(PathTuple <ModConfig> mod, PathTuple <ModUserConfig>?userConfig, UpdaterData data) { var resolvers = new List <IPackageResolver>(); var urls = new HashSet <string>(); // Get all URLs if (this.TryGetConfiguration <NuGetConfig>(mod, out var nugetConfig)) { foreach (var url in nugetConfig !.DefaultRepositoryUrls) { urls.Add(url); } if (nugetConfig.AllowUpdateFromAnyRepository) { foreach (var url in data.NuGetFeeds) { urls.Add(url); } } } else { // Allow package to be updated before cutoff date for new security policy, // or if package is older than the cutoff date. if (Now < MigrationDate || GetApproximateDateForMod(mod) < MigrationDate) { foreach (var url in data.NuGetFeeds) { urls.Add(url); } } } // Add all resolvers foreach (var url in urls) { resolvers.Add(new NuGetUpdateResolver( new NuGetUpdateResolverSettings() { AllowUnlisted = true, NugetRepository = new NuGetRepository(url), PackageId = mod.Config.ModId }, data.CommonPackageResolverSettings )); } if (resolvers.Count > 0) { return(new AggregatePackageResolver(resolvers)); } return(null); }
public bool IsCompatible(PathTuple <ModConfig> mod) { var package = Task.Run(() => _nugetRepository.GetLatestPackageDetails(mod.Config.ModId, false, true)).Result; if (package == null) { return(false); } _metadata = package; return(true); }
private void CreateUserConfigOnNewConfigCreated(PathTuple <ModConfig> tuple) { var filePath = ModUserConfig.GetUserConfigPathForMod(tuple.Config.ModId, ConfigDirectory); if (!File.Exists(filePath)) { IConfig <ModUserConfig> .ToPath(new ModUserConfig() { ModId = tuple.Config.ModId }, filePath); } }
/// <inheritdoc/> public IPackageResolver?GetResolver(PathTuple <ModConfig> mod, PathTuple <ModUserConfig>?userConfig, UpdaterData data) { if (!this.TryGetConfiguration <GameBananaConfig>(mod, out var gbConfig)) { return(null); } return(new GameBananaUpdateResolver(new GameBananaResolverConfiguration() { ItemId = (int)gbConfig !.ItemId, ModType = gbConfig.ItemType }, data.CommonPackageResolverSettings));
/// <summary> /// Returns true if any resolver is configured to save updates for this mod. /// </summary> /// <param name="mod">The mod to be served updates for.</param> /// <returns>Resolver configuration.</returns> public static bool HasAnyConfiguredResolver(PathTuple <ModConfig> mod) { foreach (var factory in All) { if (factory.TryGetConfigurationOrDefault(mod, out _)) { return(true); } } return(false); }
/// <summary> /// Returns the first appropriate resolver that can handle updating a mod. /// </summary> /// <param name="mod">The mod in question.</param> /// <param name="data">All data passed to the updater.</param> /// <returns>A resolver that can handle the mod, else null.</returns> public static IModResolver GetResolver(PathTuple <ModConfig> mod, Structures.UpdaterData data) { foreach (var resolver in new Resolvers(data).All) { if (resolver.IsCompatible(mod)) { return(resolver); } } return(null); }
private void RefreshCommands() { if (_lastApplication != null) { _lastApplication.Config.PropertyChanged -= OnAppLocationChanged; } DeployAsiLoaderCommand = new DeployAsiLoaderCommand(Application); SetApplicationImageCommand = new SetApplicationImageCommand(Application); _lastApplication = Application; _lastApplication.Config.PropertyChanged += OnAppLocationChanged; }
public SetDependenciesDialog(ModConfigService modConfigService, PathTuple <ModConfig> config) { InitializeComponent(); ViewModel = new SetDependenciesDialogViewmodel(modConfigService, config); var manipulator = new DictionaryResourceManipulator(this.Contents.Resources); _dependenciesViewSource = manipulator.Get <CollectionViewSource>("SortedDependencies"); _dependenciesViewSource.Filter += DependenciesViewSourceOnFilter; this.Closed += OnClosed; }
private static GameBananaProviderConfig TryGetGameBananaUpdateConfig(PathTuple <ApplicationConfig> appById) { try { appById.Config.PluginData.TryGetValue("GBPackageProvider", out GameBananaProviderConfig config); config ??= new GameBananaProviderConfig(); return(config); } catch (Exception) { return(new GameBananaProviderConfig()); } }
/// <inheritdoc/> public IPackageResolver?GetResolver(PathTuple <ModConfig> mod, PathTuple <ModUserConfig>?userConfig, UpdaterData data) { if (!this.TryGetConfiguration <GitHubConfig>(mod, out var githubConfig)) { return(null); } return(new GitHubReleaseResolver(new GitHubResolverConfiguration() { RepositoryName = githubConfig !.RepositoryName, UserName = githubConfig.UserName, LegacyFallbackPattern = githubConfig.AssetFileName, InheritVersionFromTag = githubConfig.UseReleaseTag }, data.CommonPackageResolverSettings));