Skip to content

Commit

Permalink
Use new hashing method and refactor WadTreeItem (#211)
Browse files Browse the repository at this point in the history
* Use new hashing method and refactor `WadTreeItem`

* aaaa
  • Loading branch information
Crauzer authored Jul 27, 2023
1 parent 6b6d5ee commit 39ab6fb
Show file tree
Hide file tree
Showing 9 changed files with 65 additions and 55 deletions.
2 changes: 1 addition & 1 deletion .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ file_header_template = unset
# this. and Me. preferences
dotnet_style_qualification_for_event = true:suggestion
dotnet_style_qualification_for_field = true
dotnet_style_qualification_for_method = false
dotnet_style_qualification_for_method = true:suggestion
dotnet_style_qualification_for_property = true:suggestion

# Language keywords vs BCL types preferences
Expand Down
24 changes: 13 additions & 11 deletions Obsidian/Data/Wad/IWadTreeParent.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
using LeagueToolkit.Core.Wad;
using LeagueToolkit.Hashing;
using System.Text.RegularExpressions;

namespace Obsidian.Data.Wad;

public interface IWadTreeParent : IWadTreePathable {
Dictionary<string, WadTreeItemModel> Items { get; }
List<WadTreeItemModel> Items { get; }
}

public static class IWadTreeParentExtensions {
Expand All @@ -16,18 +17,19 @@ WadChunk chunk
) {
// File belongs to this folder
if (pathComponents.Count() is 1) {
string name = pathComponents.First();
parent.Items.Add(name, new WadTreeFileModel(parent, name, wad, chunk));
parent.Items.Add(new WadTreeFileModel(parent, pathComponents.First(), wad, chunk));
return;
}

string folderName = pathComponents.First();
ulong folderNameHash = XxHash64Ext.Hash(folderName);

WadTreeItemModel directory = null;
lock (parent) {
directory = parent.Items.GetValueOrDefault(folderName);
directory = parent.Items.FirstOrDefault(item => item.Type is not WadTreeItemType.File && item.NameHash == folderNameHash);
if (directory is null) {
directory = new(parent, folderName);
parent.Items.Add(directory.Name, directory);
parent.Items.Add(directory);
}
}

Expand All @@ -38,7 +40,7 @@ public static IEnumerable<WadTreeItemModel> TraverseFlattenedItems(this IWadTree
if (parent.Items is null)
yield break;

foreach (var (_, item) in parent.Items) {
foreach (var item in parent.Items) {
yield return item;

foreach (WadTreeItemModel itemItem in item.TraverseFlattenedItems())
Expand All @@ -52,7 +54,7 @@ this IWadTreeParent parent
if (parent.Items is null)
yield break;

foreach (var (_, item) in parent.Items) {
foreach (var item in parent.Items) {
if (item.IsChecked)
yield return item;

Expand All @@ -69,7 +71,7 @@ public static IEnumerable<WadTreeItemModel> TraverseFlattenedVisibleItems(
if (parent.Items is null)
yield break;

foreach (var (_, item) in parent.Items) {
foreach (var item in parent.Items) {
if (!string.IsNullOrEmpty(filter)) {
// If the current item is a file we check if it matches the filter
if (item is WadTreeFileModel && DoesMatchFilter(item, filter, useRegex)) {
Expand All @@ -78,12 +80,12 @@ public static IEnumerable<WadTreeItemModel> TraverseFlattenedVisibleItems(
}

// If the current item is a folder we get filtered items and if there are none we skip
IReadOnlyList<WadTreeItemModel> filteredItems = item.TraverseFlattenedVisibleItems(
WadTreeItemModel[] filteredItems = item.TraverseFlattenedVisibleItems(
filter,
useRegex
)
.ToList();
if (filteredItems.Count is 0)
.ToArray();
if (filteredItems.Length is 0)
continue;

// Return parent only if its children are included in the filter
Expand Down
2 changes: 2 additions & 0 deletions Obsidian/Data/Wad/IWadTreePathable.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ public interface IWadTreePathable {

string Name { get; }
string Path { get; }
ulong NameHash { get; }
ulong PathHash { get; }

public bool IsWadArchive { get; }
}
Expand Down
36 changes: 16 additions & 20 deletions Obsidian/Data/Wad/WadTreeItemModel.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
using LeagueToolkit.Core.Wad;
using LeagueToolkit.Hashing;
using LeagueToolkit.Utils;
using MudBlazor;
using System.Diagnostics;
using System.Text.RegularExpressions;
using static System.Windows.Forms.VisualStyles.VisualStyleElement.ProgressBar;
using PathIO = System.IO.Path;

namespace Obsidian.Data.Wad;
Expand All @@ -23,8 +21,10 @@ public class WadTreeItemModel
public int Depth => this.GetDepth();

public Guid Id { get; } = Guid.NewGuid();
public string Name { get; set; }
public string Name { get; }
public string Path { get; }
public ulong NameHash { get; }
public ulong PathHash { get; }

public string Icon => GetIcon();

Expand All @@ -33,38 +33,34 @@ public class WadTreeItemModel
public bool IsSelected { get; set; }
public bool IsChecked { get; set; }
public bool IsExpanded { get; set; }
public bool IsWadArchive { get; }

public Dictionary<string, WadTreeItemModel> Items { get; protected set; } = new();

public bool IsWadArchive {
get {
string extension = PathIO.GetExtension(this.Name);

return extension.Contains("wad")
|| extension.Contains("client")
|| extension.Contains("server");
}
}
public List<WadTreeItemModel> Items { get; protected set; } = new();

public WadTreeItemModel(IWadTreeParent parent, string name) {
this.Parent = parent;
this.Name = name;

this.Name = name;
this.Path = parent switch {
null or WadTreeModel or { IsWadArchive: true } => name,
_ => string.Join('/', parent.Path, name)
};
this.NameHash = XxHash64Ext.Hash(this.Name);
this.PathHash = XxHash64Ext.Hash(this.Path);

this.IsWadArchive = this.Name.EndsWith(".wad", StringComparison.OrdinalIgnoreCase)
|| this.Name.EndsWith(".wad.client", StringComparison.OrdinalIgnoreCase)
|| this.Name.EndsWith(".wad.mobile", StringComparison.OrdinalIgnoreCase);
}

public void SortItems() {
if (this.Items is null)
return;

this.Items = new(this.Items.OrderBy(x => x.Value));
this.Items.Sort();

foreach (var (_, item) in this.Items) {
if (item.Type is WadTreeItemType.Directory)
item.SortItems();
foreach (WadTreeItemModel item in this.Items.Where(item => item.Type is WadTreeItemType.Directory)) {
item.SortItems();
}
}

Expand Down
34 changes: 21 additions & 13 deletions Obsidian/Data/Wad/WadTreeModel.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
using CommunityToolkit.Diagnostics;
using CommunityToolkit.HighPerformance.Helpers;
using LeagueToolkit.Core.Wad;
using Obsidian.Services;
using Obsidian.Shared;
using Serilog;
using PathIO = System.IO.Path;

Expand All @@ -14,28 +12,31 @@ public class WadTreeModel : IWadTreeParent, IDisposable {

public IWadTreeParent Parent => null;
public int Depth => 0;

public string Name => string.Empty;
public string Path => string.Empty;
public ulong NameHash => 0;
public ulong PathHash => 0;

public bool IsWadArchive => false;

public bool UseRegexFilter { get; set; }
public string Filter { get; set; }

public WadFilePreviewType CurrentPreviewType { get; set; }

public Dictionary<string, WadTreeItemModel> Items { get; set; } = new();
public List<WadTreeItemModel> Items { get; set; } = new();

public IEnumerable<WadTreeFileModel> CheckedFiles =>
this.TraverseFlattenedCheckedItems()
.Where(x => x is WadTreeFileModel)
.Select(x => x as WadTreeFileModel);
.OfType<WadTreeFileModel>();

public WadTreeFileModel SelectedFile => this.SelectedFiles.FirstOrDefault();

public IEnumerable<WadTreeFileModel> SelectedFiles =>
this.TraverseFlattenedItems()
.Where(x => x.IsSelected && x is WadTreeFileModel)
.Select(x => x as WadTreeFileModel);
.Where(x => x.IsSelected)
.OfType<WadTreeFileModel>();

private readonly Dictionary<string, WadFile> _mountedWadFiles = new();

Expand Down Expand Up @@ -69,27 +70,34 @@ private void MountWadFile(string path) {
CreateTreeForWadFile(wad, relativeWadPath);
}

public void CreateTreeForWadFile(WadFile wad, string wadFilePath) {
public void CreateTreeForWadFile(WadFile wad, string wadFilePath, bool allowDuplicate = false) {
IEnumerable<string> wadFilePathComponents = wadFilePath.Split('/');

IWadTreeParent wadParent = this;
if (allowDuplicate) {
var wadItem = new WadTreeItemModel(this, wadFilePathComponents.First());
this.Items.Add(wadItem);
wadParent = wadItem;
wadFilePathComponents = wadFilePathComponents.Skip(1);
}

foreach (var (_, chunk) in wad.Chunks) {
string path = this.Hashtable.TryGetChunkPath(chunk, out path) switch {
true => path,
false => HashtableService.GuessChunkPath(chunk, wad),
};

this.AddWadFile(wadFilePathComponents.Concat(path.Split('/')), wad, chunk);
wadParent.AddWadFile(wadFilePathComponents.Concat(path.Split('/')), wad, chunk);
}
}

public void SortItems() {
Log.Information($"Sorting wad tree");

this.Items = new(this.Items.OrderBy(x => x.Value));
this.Items.Sort();

foreach (var (_, item) in this.Items) {
if (item.Type is WadTreeItemType.Directory)
item.SortItems();
foreach (WadTreeItemModel item in this.Items.Where(item => item.Type is WadTreeItemType.Directory)) {
item.SortItems();
}
}

Expand Down
6 changes: 3 additions & 3 deletions Obsidian/Obsidian.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@
<ItemGroup>
<PackageReference Include="BlazorMonaco" Version="3.0.0" />
<PackageReference Include="CodeBeam.MudExtensions" Version="6.2.7" />
<PackageReference Include="DiscordRichPresence" Version="1.1.3.18" />
<PackageReference Include="DiscordRichPresence" Version="1.2.1.24" />
<PackageReference Include="FluentValidation" Version="11.5.2" />
<PackageReference Include="LeagueToolkit" Version="4.0.0-beta.28" />
<PackageReference Include="LeagueToolkit.IO.Extensions" Version="4.0.0-beta.28" />
<PackageReference Include="LeagueToolkit" Version="4.0.0-beta.29" />
<PackageReference Include="LeagueToolkit.IO.Extensions" Version="4.0.0-beta.29" />
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="7.0.0" />
<PackageReference Include="MudBlazor" Version="6.1.9" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
Expand Down
2 changes: 1 addition & 1 deletion Obsidian/Shared/TreeWadItem.razor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ private void Save() {
}

private void Delete() {
this.Item.Parent.Items.Remove(this.Item.Name);
this.Item.Parent.Items.Remove(this.Item);
this.Explorer.RefreshState();
}
}
10 changes: 6 additions & 4 deletions Obsidian/Shared/WadExplorer.razor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,10 @@ await Task.Run(() => {
FileStream wadFileStream = File.OpenRead(wadPath);
WadFile wad = new(wadFileStream);

this.WadTree.CreateTreeForWadFile(wad, Path.GetFileName(wadPath));
this.WadTree.CreateTreeForWadFile(wad, Path.GetFileName(wadPath), allowDuplicate: true);
}

this.WadTree.SortItems();
});

this.Snackbar.Add("Successfully opened Wad archives!", Severity.Success);
Expand Down Expand Up @@ -191,15 +193,15 @@ private void ExtractFiles(IEnumerable<WadTreeFileModel> fileItems, string extrac
);
}

public List<WadTreeItemModel> GetVisibleItemsForWadTree() {
private ICollection<WadTreeItemModel> GetVisibleItemsForWadTree() {
try {
return this.WadTree
.TraverseFlattenedVisibleItems(this.WadTree.Filter, this.WadTree.UseRegexFilter)
.ToList();
.ToArray();
} catch (Exception exception) {
SnackbarUtils.ShowSoftError(this.Snackbar, exception);

return new();
return Array.Empty<WadTreeItemModel>();
}
}

Expand Down
4 changes: 2 additions & 2 deletions Obsidian/Utils/WadUtils.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
using LeagueToolkit.Core.Wad;
using XXHash3NET;
using LeagueToolkit.Hashing;

namespace Obsidian.Utils;

Expand Down Expand Up @@ -27,7 +27,7 @@ public static string CreateChunkFilePath(string saveDirectory, string chunkPath)
saveDirectory,
string.Format(
"{0:x16}{1}",
XXHash64.Compute(chunkPath.ToLower()),
XxHash64Ext.Hash(chunkPath.ToLowerInvariant()),
Path.GetExtension(chunkPath)
)
);
Expand Down

0 comments on commit 39ab6fb

Please sign in to comment.