Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4,749 changes: 5 additions & 4,744 deletions Knossos.NET/ViewModels/Templates/TaskItemViewModel.cs

Large diffs are not rendered by default.

152 changes: 152 additions & 0 deletions Knossos.NET/ViewModels/Templates/Tasks/CompressLosseFiles.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
using Avalonia.Threading;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Threading;
using VP.NET;
using System.Text;

namespace Knossos.NET.ViewModels
{
public partial class TaskItemViewModel : ViewModelBase
{
private async Task<bool> CompressLosseFiles(List<string> filePaths, int alreadySkipped, CancellationTokenSource? cancelSource = null)
{
try
{
if (!TaskIsSet)
{
TaskIsSet = true;
ProgressBarMax = filePaths.Count();
ProgressCurrent = 0;
ShowProgressText = false;
if (cancelSource != null)
{
cancellationTokenSource = cancelSource;
}
else
{
cancellationTokenSource = new CancellationTokenSource();
}
CancelButtonVisible = false;
Name = "Compressing loose files";

if (cancellationTokenSource.IsCancellationRequested)
{
throw new TaskCanceledException();
}

int skippedCount = alreadySkipped;
int compressedCount = 0;

Log.Add(Log.LogSeverity.Information, "TaskItemViewModel.CompressLosseFiles()", "Starting to compress loose files");

await Parallel.ForEachAsync(filePaths, new ParallelOptions { MaxDegreeOfParallelism = Knossos.globalSettings.compressionMaxParallelism }, async (file, token) =>
{
var input = new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.Read);
BinaryReader br = new BinaryReader(input);

if (!input.CanRead)
{
input.Dispose();
throw new TaskCanceledException();
}

//Verify if it is compressed
if (Encoding.ASCII.GetString(br.ReadBytes(4)) != "LZ41")
{
FileInfo fi = new FileInfo(file);
await Dispatcher.UIThread.InvokeAsync(() => {
Info = ProgressCurrent + " / " + ProgressBarMax + " " + fi.Name;
});
input.Seek(0, SeekOrigin.Begin);
var output = new FileStream(fi.FullName + ".lz41", FileMode.Create, FileAccess.ReadWrite, FileShare.None);
if (!output.CanWrite)
{
input.Dispose();
output.Dispose();
throw new TaskCanceledException();
}

var compressedSize = VPCompression.CompressStream(input, output);
output.Dispose();
if (compressedSize < input.Length)
{
//Delete original
input.Dispose();
output.Dispose();
File.Delete(file);
compressedCount++;
}
else
{
//Roll back
input.Dispose();
output.Dispose();
File.Delete(fi.FullName + ".lz41");
skippedCount++;
}
}
else
{
skippedCount++;
}
await input.DisposeAsync();
ProgressCurrent++;

if (cancellationTokenSource.IsCancellationRequested)
{
throw new TaskCanceledException();
}
});
if (cancellationTokenSource.IsCancellationRequested)
{
throw new TaskCanceledException();
}

IsCompleted = true;
ProgressCurrent = ProgressBarMax;
Info = "Compressed: " + compressedCount + " Skipped: " + skippedCount;
Log.Add(Log.LogSeverity.Information, "TaskItemViewModel.CompressLosseFiles()", "Compressing Loose files finished: " + Info);
return true;
}
else
{
throw new Exception("The task is already set, it cant be changed or re-assigned.");
}
}
catch (TaskCanceledException)
{
/*
Task cancel requested by user
*/
IsCompleted = false;
IsCancelled = true;
CancelButtonVisible = false;
Info = "Task Cancelled";
//Only dispose the token if it was created locally
if (cancelSource == null)
{
cancellationTokenSource?.Dispose();
}
return false;
}
catch (Exception ex)
{
IsCompleted = false;
CancelButtonVisible = false;
IsCancelled = true;
Info = "Task Failed";
//Only dispose the token if it was created locally
if (cancelSource == null)
{
cancellationTokenSource?.Dispose();
}
Log.Add(Log.LogSeverity.Warning, "TaskItemViewModel.CompressLosseFiles()", ex);
return false;
}
}
}
}
206 changes: 206 additions & 0 deletions Knossos.NET/ViewModels/Templates/Tasks/CompressMod.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
using Avalonia.Threading;
using Knossos.NET.Models;
using System;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Threading;
using VP.NET;

namespace Knossos.NET.ViewModels
{
public partial class TaskItemViewModel : ViewModelBase
{
public async Task<bool> CompressMod(Mod mod, CancellationTokenSource? cancelSource = null, bool isSubTask = false)
{
try
{
if (!TaskIsSet)
{
TaskIsSet = true;
if (!isSubTask)
{
CancelButtonVisible = true;
Name = "Compressing mod: " + mod.title + " " + mod.version;
}
else
{
Name = "Compressing mod";
}

ShowProgressText = false;
await Dispatcher.UIThread.InvokeAsync(() => {
TaskRoot.Add(this);
});
ProgressBarMin = 0;
ProgressCurrent = 0;
Info = "In Queue";

if (cancelSource != null)
{
cancellationTokenSource = cancelSource;
}
else
{
cancellationTokenSource = new CancellationTokenSource();
}

//Wait in Queue
if (!isSubTask)
{
while (TaskViewModel.Instance!.taskQueue.Count > 0 && TaskViewModel.Instance!.taskQueue.Peek() != this)
{
await Task.Delay(1000);
if (cancellationTokenSource.IsCancellationRequested)
{
throw new TaskCanceledException();
}
}
}

Log.Add(Log.LogSeverity.Information, "TaskItemViewModel.CompressMod()", "Starting to compress Mod: " + mod.title);

var vpFiles = Directory.GetFiles(mod.fullPath, "*.vp").ToList();
ProgressBarMax = vpFiles.Count() + 1;

//Loose Files Compression
if (Directory.Exists(mod.fullPath + Path.DirectorySeparatorChar + "data") || mod.devMode)
{
var searchDir = mod.devMode ? mod.fullPath : mod.fullPath + Path.DirectorySeparatorChar + "data";
var allFilesInDataFolder = Directory.GetFiles(searchDir, "*.*", SearchOption.AllDirectories).ToList();
int skipped = 0;
//Filter
foreach (var fileInData in allFilesInDataFolder.ToList())
{
var file = new FileInfo(fileInData);

if (file.IsReadOnly || file.Length < VPCompression.MinimumSize || VPCompression.ExtensionIgnoreList.Contains(file.Extension.ToLower()) || file.Extension.ToLower() == ".lz41")
{
if (file.Extension.ToLower() == ".vp")
{
vpFiles.Add(fileInData);
ProgressBarMax++;
}
allFilesInDataFolder.Remove(fileInData);
skipped++;
}
}
//Process
await Dispatcher.UIThread.InvokeAsync(async () =>
{
var fileTask = new TaskItemViewModel();
await Dispatcher.UIThread.InvokeAsync(() =>
{
TaskList.Insert(0, fileTask);
});

Info = "Tasks: " + ProgressCurrent + "/" + ProgressBarMax;

var result = await fileTask.CompressLosseFiles(allFilesInDataFolder, skipped, cancellationTokenSource);
if (cancellationTokenSource.IsCancellationRequested)
{
throw new TaskCanceledException();
}
}, DispatcherPriority.Background);
}
ProgressCurrent++;
Info = "Tasks: " + ProgressCurrent + "/" + ProgressBarMax;

//VP Compression
await Parallel.ForEachAsync(vpFiles, new ParallelOptions { MaxDegreeOfParallelism = Knossos.globalSettings.compressionMaxParallelism }, async (file, token) =>
{
await Dispatcher.UIThread.InvokeAsync(async () =>
{
var vpTask = new TaskItemViewModel();
await Dispatcher.UIThread.InvokeAsync(() =>
{
TaskList.Insert(0, vpTask);
});
Info = "Tasks: " + ProgressCurrent + "/" + ProgressBarMax;
await vpTask.CompressVP(new FileInfo(file), cancellationTokenSource);
ProgressCurrent++;
Info = "Tasks: " + ProgressCurrent + "/" + ProgressBarMax;
if (cancellationTokenSource.IsCancellationRequested)
{
throw new TaskCanceledException();
}
}, DispatcherPriority.Background);
});

if (cancellationTokenSource.IsCancellationRequested)
{
throw new TaskCanceledException();
}

//Update settings json
mod.modSettings.Load(mod.fullPath);
mod.modSettings.isCompressed = true;
mod.modSettings.Save();

IsCompleted = true;
ProgressCurrent = ProgressBarMax;
Info = string.Empty;
CancelButtonVisible = false;

if (!isSubTask && TaskViewModel.Instance!.taskQueue.Count > 0 && TaskViewModel.Instance!.taskQueue.Peek() == this)
{
TaskViewModel.Instance!.taskQueue.Dequeue();
}

return true;
}
else
{
throw new Exception("The task is already set, it cant be changed or re-assigned.");
}
}
catch (TaskCanceledException)
{
Info = "Task Cancelled";
IsCompleted = false;
CancelButtonVisible = false;
//Only dispose the token if it was created locally
if (cancelSource == null)
{
cancellationTokenSource?.Dispose();
}
if (!isSubTask)
{
while (TaskViewModel.Instance!.taskQueue.Count > 0 && TaskViewModel.Instance!.taskQueue.Peek() != this)
{
await Task.Delay(500);
}
if (TaskViewModel.Instance!.taskQueue.Count > 0 && TaskViewModel.Instance!.taskQueue.Peek() == this)
{
TaskViewModel.Instance!.taskQueue.Dequeue();
}
}
return false;
}
catch (Exception ex)
{
Info = "Task Failed";
IsCompleted = false;
CancelButtonVisible = false;
cancellationTokenSource?.Cancel();
if (cancelSource == null)
{
cancellationTokenSource?.Dispose();
}
if (!isSubTask)
{
while (TaskViewModel.Instance!.taskQueue.Count > 0 && TaskViewModel.Instance!.taskQueue.Peek() != this)
{
await Task.Delay(500);
}
if (TaskViewModel.Instance!.taskQueue.Count > 0 && TaskViewModel.Instance!.taskQueue.Peek() == this)
{
TaskViewModel.Instance!.taskQueue.Dequeue();
}
}
Log.Add(Log.LogSeverity.Error, "TaskItemViewModel.CompressMod()", ex);
return false;
}
}
}
}
Loading