void ConfigureVersionButton(Button versionButton, PackageGroup selection) { versionButton.clickable.clickedWithEventInfo -= PickVersion; versionButton.clickable.clickedWithEventInfo += PickVersion; versionButton.userData = selection; versionButton.text = targetVersion; versionButton.SetEnabled(!selection.Installed); }
public override ulong SolvePart1() { int targetWeight = packageWeights.Sum() / 3; GetMinMaxGroupSize(targetWeight, out int minGroupSize, out int maxGroupSize); // Start finding the groups int group1Size = minGroupSize; PackageGroup bestGroup = null; ulong bestGroupQE = ulong.MaxValue; var packageWeightsSet = new HashSet <int>(packageWeights); var groupDictionary = new FlexibleDictionary <int, HashSet <int>[]>(); while (true) { foreach (var group1 in GetGroups(group1Size)) { var remainingWeights = new HashSet <int>(packageWeightsSet); remainingWeights.ExceptWith(group1); int maxGroup2Size = maxGroupSize - (packageWeightsSet.Count - remainingWeights.Count); for (int group2Size = minGroupSize; group2Size < maxGroup2Size; group2Size++) { if (GetGroups(group2Size).Any(group => !remainingWeights.Overlaps(group))) { EvaluateBestGroup(new(group1), ref bestGroup, ref bestGroupQE); break; } } } if (bestGroup is not null) { return(bestGroupQE); } group1Size++; } IEnumerable <HashSet <int> > GetGroups(int size) { if (!groupDictionary.ContainsKey(size)) { groupDictionary[size] = FindGroups(size, targetWeight, packageWeights); } return(groupDictionary[size]); } }
private void AddGamePage(string alias, WarcraftVersion version, PackageGroup group, SerializedTree nodeTree) { var page = new GamePage(group, nodeTree, version, alias); page.FileLoadRequested += OnFileLoadRequested; page.SaveRequested += OnSaveRequested; page.ExportItemRequested += OnExportItemRequested; page.EnqueueFileExportRequested += OnEnqueueItemRequested; _gamePages.Add(page); _gameTabNotebook.AppendPage(page.PageWidget, new Label(page.Alias)); _gameTabNotebook.SetTabReorderable(page.PageWidget, true); _gameTabNotebook.ShowAll(); }
private void AddGamePage(string alias, WarcraftVersion version, PackageGroup group, OptimizedNodeTree nodeTree) { GamePage page = new GamePage(group, nodeTree, version); page.Alias = alias; page.FileLoadRequested += OnFileLoadRequested; page.ExportItemRequested += OnExportItemRequested; page.EnqueueFileExportRequested += OnEnqueueItemRequested; this.GamePages.Add(page); this.GameTabNotebook.AppendPage(page.PageWidget, new Label(page.Alias)); this.GameTabNotebook.SetTabReorderable(page.PageWidget, true); this.GameTabNotebook.ShowAll(); }
/// <summary> /// Gets a <see cref="FileReference"/> from a given iter in the tree. /// </summary> /// <param name="packageGroup">The package group to create a reference for.</param> /// <param name="iter">The iter in the tree.</param> /// <returns>The FileReference pointed to by the given iter.</returns> /// <exception cref="InvalidDataException">Thrown if the iter doesn't belong to the model.</exception> public FileReference GetReferenceByIter(PackageGroup packageGroup, TreeIter iter) { if (iter.Stamp != this.Stamp) { throw new InvalidDataException("The given iter was not valid for this model."); } FileNode node = this.Tree.GetNode((ulong)iter.UserData); if (node == null) { return(null); } return(new FileReference(packageGroup, node, GetNodePackage(node), GetNodeFilePath(node))); }
public PackageVersionGenerator( AbsolutePath tracerDirectory, AbsolutePath testProjectDirectory) { var propsDirectory = tracerDirectory / "build"; _definitionsFilePath = tracerDirectory / "build" / "PackageVersionsGeneratorDefinitions.json"; _latestMinors = new PackageGroup(propsDirectory, testProjectDirectory, "LatestMinors"); _latestMajors = new PackageGroup(propsDirectory, testProjectDirectory, "LatestMajors"); _strategyGenerator = new XunitStrategyFileGenerator(testProjectDirectory / "PackageVersions.g.cs"); if (!File.Exists(_definitionsFilePath)) { throw new Exception($"Definitions file {_definitionsFilePath} does not exist. Exiting."); } }
/// <summary> /// Initializes a new instance of the <see cref="RenderableWorldModel"/> class. /// </summary> public RenderableWorldModel(WMO inModel, PackageGroup inPackageGroup) { this.Model = inModel; this.ModelPackageGroup = inPackageGroup; this.ActorTransform = new Transform ( new Vector3(0.0f, 0.0f, 0.0f), Quaternion.FromAxisAngle(Vector3.UnitX, MathHelper.Pi), new Vector3(1.0f, 1.0f, 1.0f) ); this.IsInitialized = false; Initialize(); }
/// <summary> /// Initializes a new instance of the <see cref="RenderableWorldModel"/> class. /// </summary> /// <param name="inModel">The model to render.</param> /// <param name="inPackageGroup">The package group the model belongs to.</param> /// <param name="inVersion">The game version of the package group.</param> public RenderableWorldModel(WMO inModel, PackageGroup inPackageGroup, WarcraftVersion inVersion) { this.Model = inModel; this.ModelPackageGroup = inPackageGroup; this.DatabaseProvider = new ClientDatabaseProvider(inVersion, this.ModelPackageGroup); this.ActorTransform = new Transform ( new Vector3(0.0f, 0.0f, 0.0f), Quaternion.FromAxisAngle(Vector3.UnitX, MathHelper.Pi), new Vector3(1.0f, 1.0f, 1.0f) ); this.IsInitialized = false; Initialize(); }
private void BindPackageView(PackageGroup selection) { if (selection.Installed) { targetVersion = PackageHelper.GetPackageManagerManifest(selection.PackageDirectory).version; } else { targetVersion = selection["latest"].version; } ConfigureVersionButton(packageView.Q <Button>("tkpm-package-version-button"), selection); ConfigureInstallButton(packageView.Q <Button>("tkpm-package-install-button"), selection); RepopulateLabels(packageView.Q("tkpm-package-tags"), selection.Tags, "tag"); var selectedVersion = selection[targetVersion]; var pvDependencies = selectedVersion.dependencies ?? Array.Empty <PackageVersion>(); var dependencyIds = new List <string>(); foreach (var pvd in pvDependencies) { dependencyIds.Add(pvd.dependencyId); } var texts = dependencyIds ?? Enumerable.Empty <string>(); RepopulateLabels(packageView.Q("tkpm-package-dependencies"), texts, "dependency"); SetLabel(packageView, "tkpm-package-title", NicifyPackageName(selection.PackageName)); SetLabel(packageView, "tkpm-package-name", selection.DependencyId); if (selection.Installed) { SetLabel(packageView, "tkpm-package-info-version-value", selection.InstalledVersion); } else { SetLabel(packageView, "tkpm-package-info-version-value", selection["latest"].version); } SetLabel(packageView, "tkpm-package-author-value", selection.Author); SetLabel(packageView, "tkpm-package-description", selection.Description); }
/// <summary> /// Attempts to load a game in a specified path, returning a <see cref="PackageGroup"/> object with the /// packages in the path and an <see cref="SerializedTree"/> with a fully qualified node tree of the /// package group. /// If no packages are found, then this method will return null in both fields. /// </summary> /// <param name="gameAlias">The alias of the game at the path.</param> /// <param name="gamePath">The path to load as a game.</param> /// <param name="ct">A cancellation token.</param> /// <param name="progress">An <see cref="IProgress{GameLoadingProgress}"/> object for progress reporting.</param> /// <returns>A tuple with a package group and a node tree for the requested game.</returns> public async Task <(PackageGroup?packageGroup, SerializedTree?nodeTree)> LoadGameAsync ( string gameAlias, string gamePath, CancellationToken ct, IProgress <GameLoadingProgress>?progress = null ) { progress?.Report(new GameLoadingProgress { CompletionPercentage = 0.0f, State = GameLoadingState.SettingUp, Alias = gameAlias }); var packagePaths = Directory.EnumerateFiles ( gamePath, "*", SearchOption.AllDirectories ) .Where(p => p.EndsWith(".mpq", StringComparison.InvariantCultureIgnoreCase)) .OrderBy(p => p) .ToList(); if (packagePaths.Count == 0) { return(null, null); } var packageSetHash = GeneratePathSetHash(packagePaths); var packageTreeFilename = $".{packageSetHash}.tree"; var packageTreeFilePath = Path.Combine(gamePath, packageTreeFilename); var packageGroup = new PackageGroup(packageSetHash); SerializedTree?nodeTree = null; var generateTree = true; if (File.Exists(packageTreeFilePath)) { progress?.Report(new GameLoadingProgress { CompletionPercentage = 0, State = GameLoadingState.LoadingNodeTree, Alias = gameAlias }); try { // Load tree nodeTree = new SerializedTree(File.OpenRead(packageTreeFilePath)); generateTree = false; } catch (FileNotFoundException) { Log.Error("No file for the node tree found at the given location."); } catch (NotSupportedException) { Log.Info("Unsupported node tree version present. Deleting and regenerating."); File.Delete(packageTreeFilePath); } } if (generateTree) { // Internal counters for progress reporting double completedSteps = 0; double totalSteps = packagePaths.Count * 2; // Load packages var packages = new List <(string packageName, IPackage package)>(); foreach (var packagePath in packagePaths) { ct.ThrowIfCancellationRequested(); progress?.Report(new GameLoadingProgress { CompletionPercentage = completedSteps / totalSteps, State = GameLoadingState.LoadingPackages, Alias = gameAlias }); try { var package = await PackageInteractionHandler.LoadAsync(packagePath); packages.Add((Path.GetFileNameWithoutExtension(packagePath), package)); } catch (FileLoadException fex) { Log.Warn($"Failed to load archive {Path.GetFileNameWithoutExtension(packagePath)}: {fex.Message}"); } ++completedSteps; } // Load dictionary if neccesary if (_dictionary == null) { progress?.Report(new GameLoadingProgress { CompletionPercentage = completedSteps / totalSteps, State = GameLoadingState.LoadingDictionary, Alias = gameAlias }); _dictionary = await LoadDictionaryAsync(ct); } // Generate node tree var builder = new TreeBuilder(); foreach (var packageInfo in packages) { ct.ThrowIfCancellationRequested(); progress?.Report(new GameLoadingProgress { CompletionPercentage = completedSteps / totalSteps, State = GameLoadingState.BuildingNodeTree, Alias = gameAlias }); var steps = completedSteps; var createNodesProgress = new Progress <PackageNodesCreationProgress> ( p => { progress?.Report ( new GameLoadingProgress { CompletionPercentage = steps / totalSteps, State = GameLoadingState.BuildingNodeTree, Alias = gameAlias, CurrentPackage = packageInfo.packageName, NodesCreationProgress = p } ); } ); await Task.Run(() => builder.AddPackage(packageInfo.packageName, packageInfo.package, createNodesProgress, ct), ct); packageGroup.AddPackage((PackageInteractionHandler)packageInfo.package); ++completedSteps; } // Build node tree var tree = builder.GetTree(); var optimizeTreeProgress = new Progress <TreeOptimizationProgress> ( p => { progress?.Report ( new GameLoadingProgress { CompletionPercentage = completedSteps / totalSteps, State = GameLoadingState.BuildingNodeTree, Alias = gameAlias, OptimizationProgress = p } ); } ); var optimizer = new TreeOptimizer(_dictionary); var treeClosureCopy = tree; tree = await Task.Run(() => optimizer.OptimizeTree(treeClosureCopy, optimizeTreeProgress, ct), ct); using (var fs = File.OpenWrite(packageTreeFilePath)) { using (var serializer = new TreeSerializer(fs)) { await serializer.SerializeAsync(tree, ct); } } nodeTree = new SerializedTree(File.OpenRead(packageTreeFilePath)); } else { progress?.Report(new GameLoadingProgress { CompletionPercentage = 1, State = GameLoadingState.LoadingPackages, Alias = gameAlias }); // Load packages packageGroup = await PackageGroup.LoadAsync(gameAlias, packageSetHash, gamePath, ct, progress); } progress?.Report(new GameLoadingProgress { CompletionPercentage = 1, State = GameLoadingState.Loading, Alias = gameAlias }); return(packageGroup, nodeTree); }
/// <summary> /// Loads all packages in the currently selected game directory. This function does not enumerate files /// and directories deeper than one to keep the UI responsive. /// </summary> private void Reload_Implementation() { if (!HasPackageDirectoryChanged()) { return; } this.CachedPackageDirectories = GamePathStorage.Instance.GamePaths; this.PackageGroups.Clear(); if (this.CachedPackageDirectories.Count > 0) { this.WorkQueue.Clear(); this.NodeStorage.Clear(); } foreach (string packageDirectory in this.CachedPackageDirectories) { if (!Directory.Exists(packageDirectory)) { continue; } // Create the package group and add it to the available ones string folderName = Path.GetFileName(packageDirectory); PackageGroup packageGroup = new PackageGroup(folderName, packageDirectory); // TODO: Creating a package group is real slow. Speed it up this.PackageGroups.Add(folderName, packageGroup); // Create a virtual item reference that points to the package group VirtualFileReference packageGroupReference = new VirtualFileReference(packageGroup, new FileReference(packageGroup)) { State = ReferenceState.Enumerating }; // Create a virtual package folder for the individual packages under the package group FileReference packageGroupPackagesFolderReference = new FileReference(packageGroup, packageGroupReference, ""); // Add the package folder as a child to the package group node packageGroupReference.ChildReferences.Add(packageGroupPackagesFolderReference); // Send the package group node to the UI this.PackageGroupAddedArgs = new ReferenceEnumeratedEventArgs(packageGroupReference); RaisePackageGroupAdded(); // Add the packages in the package group as nodes to the package folder foreach (KeyValuePair <string, List <string> > packageListFile in packageGroup.PackageListfiles) { if (packageListFile.Value == null) { continue; } string packageName = Path.GetFileName(packageListFile.Key); FileReference packageReference = new FileReference(packageGroup, packageGroupPackagesFolderReference, packageName, ""); // Send the package node to the UI this.PackageEnumeratedArgs = new ReferenceEnumeratedEventArgs(packageReference); RaisePackageEnumerated(); // Submit the package as a work order, enumerating the topmost directories SubmitWork(packageReference); } } this.IsReloading = false; this.ArePackageGroupsLoaded = true; }
/// <summary> /// Initializes a new instance of the <see cref="FileReference"/> class. /// </summary> /// <param name="inPackageGroup">PackageGroup.</param> public FileReference(PackageGroup inPackageGroup) { this.PackageGroup = inPackageGroup; }
/// <summary> /// Initializes a new instance of the <see cref="FileReference"/> class. /// </summary> /// <param name="packageGroup">PackageGroup.</param> public FileReference(PackageGroup packageGroup) { this.PackageGroup = packageGroup; }
/// <summary> /// Initializes a new instance of the <see cref="Everlook.Explorer.VirtualItemReference"/> class, /// where the reference has a parent <see cref="Everlook.Explorer.VirtualItemReference"/>. /// </summary> /// <param name="parentVirtualReference">Parent virtual reference.</param> /// <param name="inPackageGroup">In group.</param> /// <param name="inHardReference">In hard reference.</param> public VirtualItemReference(VirtualItemReference parentVirtualReference, PackageGroup inPackageGroup, ItemReference inHardReference) : this(inPackageGroup, inHardReference) { this.ParentReference = parentVirtualReference; }
/// <summary> /// Initializes a new instance of the <see cref="GamePage"/> class. The given package group and node tree are /// wrapped by the page. /// </summary> /// <param name="packageGroup">The package group which the node tree maps to.</param> /// <param name="nodeTree">The prebuilt node tree to display.</param> /// <param name="version">The Warcraft version that the game page is contextually relevant for.</param> public GamePage(PackageGroup packageGroup, OptimizedNodeTree nodeTree, WarcraftVersion version) { this.Packages = packageGroup; this.Version = version; this.DatabaseProvider = new ClientDatabaseProvider(this.Version, this.Packages); this.TreeModel = new FileTreeModel(nodeTree); this.TreeAlignment = new Alignment(0.5f, 0.5f, 1.0f, 1.0f) { TopPadding = 1, BottomPadding = 1 }; this.TreeFilter = new TreeModelFilter(new TreeModelAdapter(this.TreeModel), null) { VisibleFunc = TreeModelVisibilityFunc }; this.TreeSorter = new TreeModelSort(this.TreeFilter); this.TreeSorter.SetSortFunc(0, SortGameTreeRow); this.TreeSorter.SetSortColumnId(0, SortType.Descending); this.Tree = new TreeView(this.TreeSorter) { HeadersVisible = true, EnableTreeLines = true }; CellRendererPixbuf nodeIconRenderer = new CellRendererPixbuf { Xalign = 0.0f }; CellRendererText nodeNameRenderer = new CellRendererText { Xalign = 0.0f }; TreeViewColumn column = new TreeViewColumn { Title = "Data Files", Spacing = 4 }; column.PackStart(nodeIconRenderer, false); column.PackStart(nodeNameRenderer, false); column.SetCellDataFunc(nodeIconRenderer, RenderNodeIcon); column.SetCellDataFunc(nodeNameRenderer, RenderNodeName); this.Tree.AppendColumn(column); ScrolledWindow sw = new ScrolledWindow { this.Tree }; this.TreeAlignment.Add(sw); this.Tree.RowActivated += OnRowActivated; this.Tree.ButtonPressEvent += OnButtonPressed; this.Tree.Selection.Changed += OnSelectionChanged; this.TreeContextMenu = new Menu(); // Save item context button this.SaveItem = new ImageMenuItem { UseStock = true, Label = Stock.Save, CanFocus = false, TooltipText = "Save the currently selected item to disk.", UseUnderline = true }; this.SaveItem.Activated += OnSaveItem; this.TreeContextMenu.Add(this.SaveItem); // Export item context button this.ExportItem = new ImageMenuItem("Export") { Image = new Image(Stock.Convert, IconSize.Button), CanFocus = false, TooltipText = "Exports the currently selected item to another format.", }; this.ExportItem.Activated += OnExportItemRequested; this.TreeContextMenu.Add(this.ExportItem); // Open item context button this.OpenItem = new ImageMenuItem { UseStock = true, Label = Stock.Open, CanFocus = false, TooltipText = "Open the currently selected item.", UseUnderline = true }; this.OpenItem.Activated += OnOpenItem; this.TreeContextMenu.Add(this.OpenItem); // Queue for export context button this.QueueForExportItem = new ImageMenuItem("Queue for export") { Image = new Image(Stock.Convert, IconSize.Button), CanFocus = false, TooltipText = "Queues the currently selected item for batch export.", }; this.QueueForExportItem.Activated += OnQueueForExportRequested; this.TreeContextMenu.Add(this.QueueForExportItem); // Separator SeparatorMenuItem separator = new SeparatorMenuItem(); this.TreeContextMenu.Add(separator); // Copy path context button this.CopyPathItem = new ImageMenuItem("Copy path") { Image = new Image(Stock.Copy, IconSize.Button), CanFocus = false, TooltipText = "Copy the path of the currently selected item.", }; this.CopyPathItem.Activated += OnCopyPath; this.TreeContextMenu.Add(this.CopyPathItem); this.TreeAlignment.ShowAll(); }
/// <summary> /// Initializes a new instance of the <see cref="Everlook.Explorer.ItemReference"/> class. /// </summary> /// <param name="inPackageGroup">PackageGroup.</param> public ItemReference(PackageGroup inPackageGroup) { this.PackageGroup = inPackageGroup; }
public void Add(PackageGroup aPackageGroup) { List.Add(aPackageGroup); }
public SetPackageGroupingCommand(PackageGroup groupMode) { GroupMode = groupMode; }
/// <summary> /// Attempts to load a game in a specified path, returning a <see cref="PackageGroup"/> object with the /// packages in the path and an <see cref="OptimizedNodeTree"/> with a fully qualified node tree of the /// package group. /// If no packages are found, then this method will return null in both fields. /// </summary> /// <param name="gameAlias">The alias of the game at the path.</param> /// <param name="gamePath">The path to load as a game.</param> /// <param name="ct">A cancellation token.</param> /// <param name="progress">An <see cref="IProgress{GameLoadingProgress}"/> object for progress reporting.</param> /// <returns>A tuple with a package group and a node tree for the requested game.</returns> public async Task <(PackageGroup packageGroup, OptimizedNodeTree nodeTree)> LoadGameAsync( string gameAlias, string gamePath, CancellationToken ct, IProgress <GameLoadingProgress> progress = null) { progress?.Report(new GameLoadingProgress { CompletionPercentage = 0.0f, State = GameLoadingState.SettingUp, Alias = gameAlias }); List <string> packagePaths = Directory.EnumerateFiles ( gamePath, "*", SearchOption.AllDirectories ) .Where(p => p.EndsWith(".mpq", StringComparison.InvariantCultureIgnoreCase)) .OrderBy(p => p) .ToList(); if (packagePaths.Count == 0) { return(null, null); } string packageSetHash = GeneratePathSetHash(packagePaths); string packageTreeFilename = $".{packageSetHash}.tree"; string packageTreeFilePath = Path.Combine(gamePath, packageTreeFilename); PackageGroup packageGroup = new PackageGroup(packageSetHash); OptimizedNodeTree nodeTree = null; bool generateTree = true; if (File.Exists(packageTreeFilePath)) { progress?.Report(new GameLoadingProgress { CompletionPercentage = 0, State = GameLoadingState.LoadingNodeTree, Alias = gameAlias }); try { // Load tree nodeTree = new OptimizedNodeTree(packageTreeFilePath); generateTree = false; } catch (NodeTreeNotFoundException) { Log.Error("No file for the node tree found at the given location."); } catch (UnsupportedNodeTreeVersionException) { Log.Info("Unsupported node tree version present. Deleting and regenerating."); File.Delete(packageTreeFilePath); } } if (generateTree) { // Internal counters for progress reporting double completedSteps = 0; double totalSteps = packagePaths.Count * 2; // Load packages List <(string packageName, IPackage package)> packages = new List <(string packageName, IPackage package)>(); foreach (string packagePath in packagePaths) { ct.ThrowIfCancellationRequested(); progress?.Report(new GameLoadingProgress { CompletionPercentage = completedSteps / totalSteps, State = GameLoadingState.LoadingPackages, Alias = gameAlias }); try { PackageInteractionHandler package = await PackageInteractionHandler.LoadAsync(packagePath); packages.Add((Path.GetFileNameWithoutExtension(packagePath), package)); } catch (FileLoadException fex) { Log.Warn($"Failed to load archive {Path.GetFileNameWithoutExtension(packagePath)}: {fex.Message}"); } ++completedSteps; } // Load dictionary if neccesary if (this.Dictionary == null) { progress?.Report(new GameLoadingProgress { CompletionPercentage = completedSteps / totalSteps, State = GameLoadingState.LoadingDictionary, Alias = gameAlias }); this.Dictionary = await LoadDictionaryAsync(ct); } // Generate node tree MultiPackageNodeTreeBuilder multiBuilder = new MultiPackageNodeTreeBuilder(this.Dictionary); foreach (var packageInfo in packages) { ct.ThrowIfCancellationRequested(); progress?.Report(new GameLoadingProgress { CompletionPercentage = completedSteps / totalSteps, State = GameLoadingState.BuildingNodeTree, Alias = gameAlias }); await multiBuilder.ConsumePackageAsync(packageInfo.packageName, packageInfo.package, ct); packageGroup.AddPackage((PackageInteractionHandler)packageInfo.package); ++completedSteps; } // Build node tree multiBuilder.Build(); // Save it to disk File.WriteAllBytes(packageTreeFilePath, multiBuilder.CreateTree()); nodeTree = new OptimizedNodeTree(packageTreeFilePath); } else { progress?.Report(new GameLoadingProgress { CompletionPercentage = 1, State = GameLoadingState.LoadingPackages, Alias = gameAlias }); // Load packages packageGroup = await PackageGroup.LoadAsync(gameAlias, packageSetHash, gamePath, ct, progress); } progress?.Report(new GameLoadingProgress { CompletionPercentage = 1, State = GameLoadingState.Loading, Alias = gameAlias }); return(packageGroup, nodeTree); }