mirror of
https://github.com/4sval/FModel.git
synced 2026-04-16 22:46:09 -05:00
548 lines
29 KiB
C#
548 lines
29 KiB
C#
using System;
|
|
using System.Linq;
|
|
using System.Collections.Generic;
|
|
using FModel.ViewModels.ImageBox;
|
|
using Newtonsoft.Json;
|
|
using FModel.Logger;
|
|
using System.IO;
|
|
using FModel.ViewModels.AvalonEdit;
|
|
using System.Threading.Tasks;
|
|
using FModel.ViewModels.StatusBar;
|
|
using System.Collections;
|
|
using FModel.ViewModels.ListBox;
|
|
using System.Diagnostics;
|
|
using FModel.Windows.SoundPlayer;
|
|
using System.Windows;
|
|
using FModel.Windows.CustomNotifier;
|
|
using FModel.ViewModels.Buttons;
|
|
using System.Threading;
|
|
using SkiaSharp;
|
|
using System.Text;
|
|
using FModel.ViewModels.DataGrid;
|
|
using ICSharpCode.AvalonEdit.Highlighting;
|
|
using static FModel.Creator.Creator;
|
|
using System.Runtime.CompilerServices;
|
|
using FModel.PakReader;
|
|
using FModel.PakReader.IO;
|
|
using FModel.PakReader.Pak;
|
|
using FModel.PakReader.Parsers.Class;
|
|
using FModel.PakReader.Parsers.Objects;
|
|
|
|
namespace FModel.Utils
|
|
{
|
|
static class Assets
|
|
{
|
|
/// <summary>
|
|
/// used to cache assets
|
|
/// PakPackage to get the properties of the asset
|
|
/// ArraySegment<byte>[] to export the raw data
|
|
/// </summary>
|
|
private static readonly Dictionary<ReaderEntry, Dictionary<Package, ArraySegment<byte>[]>> _CachedFiles = new Dictionary<ReaderEntry, Dictionary<Package, ArraySegment<byte>[]>>();
|
|
private static Stopwatch _timer;
|
|
|
|
public static void ClearCachedFiles() => _CachedFiles.Clear();
|
|
|
|
/// <summary>
|
|
/// USER SELECTION ARRAY WILL BREAK AT THE FIRST ERROR
|
|
/// This won't happen for other type of extraction like in diff mode where we have to skip errors
|
|
/// </summary>
|
|
/// <param name="selection"></param>
|
|
/// <returns></returns>
|
|
public static async Task GetUserSelection(IList selection)
|
|
{
|
|
_timer = Stopwatch.StartNew();
|
|
ImageBoxVm.imageBoxViewModel.Reset();
|
|
AvalonEditVm.avalonEditViewModel.Reset();
|
|
ExtractStopVm.stopViewModel.IsEnabled = true;
|
|
ExtractStopVm.extractViewModel.IsEnabled = false;
|
|
StatusBarVm.statusBarViewModel.Set(string.Empty, Properties.Resources.Loading);
|
|
Tasks.TokenSource = new CancellationTokenSource();
|
|
|
|
await Task.Run(() =>
|
|
{
|
|
foreach (var item in selection)
|
|
{
|
|
if (Tasks.TokenSource.IsCancellationRequested)
|
|
throw new TaskCanceledException(Properties.Resources.Canceled);
|
|
|
|
Thread.Sleep(10); // this is actually useful because it smh unfreeze the ui so the user can cancel even tho it's a Task so...
|
|
if (item is ListBoxViewModel selected)
|
|
{
|
|
FFileIoStoreReader io = null;
|
|
if (Globals.CachedPakFiles.TryGetValue(selected.ReaderEntry.ContainerName, out var r) || Globals.CachedIoStores.TryGetValue(selected.ReaderEntry.ContainerName, out io))
|
|
{
|
|
string mount = r != null ? r.MountPoint : io!.MountPoint;
|
|
string ext = selected.ReaderEntry.GetExtension();
|
|
switch (ext)
|
|
{
|
|
case ".ini":
|
|
case ".txt":
|
|
case ".bat":
|
|
case ".xml":
|
|
case ".h":
|
|
case ".uproject":
|
|
case ".uplugin":
|
|
case ".upluginmanifest":
|
|
case ".csv":
|
|
case ".json":
|
|
{
|
|
IHighlightingDefinition syntax = ext switch
|
|
{
|
|
".ini" => AvalonEditVm.IniHighlighter,
|
|
".txt" => AvalonEditVm.IniHighlighter,
|
|
".bat" => AvalonEditVm.IniHighlighter,
|
|
".csv" => AvalonEditVm.IniHighlighter,
|
|
".xml" => AvalonEditVm.XmlHighlighter,
|
|
".h" => AvalonEditVm.CppHighlighter,
|
|
_ => AvalonEditVm.JsonHighlighter
|
|
};
|
|
using var asset = GetMemoryStream(selected.ReaderEntry.ContainerName, mount + selected.ReaderEntry.GetPathWithoutExtension());
|
|
asset.Position = 0;
|
|
using var reader = new StreamReader(asset);
|
|
AvalonEditVm.avalonEditViewModel.Set(reader.ReadToEnd(), mount + selected.ReaderEntry.Name, syntax);
|
|
break;
|
|
}
|
|
case ".locmeta":
|
|
{
|
|
using var asset = GetMemoryStream(selected.ReaderEntry.ContainerName, mount + selected.ReaderEntry.GetPathWithoutExtension());
|
|
asset.Position = 0;
|
|
AvalonEditVm.avalonEditViewModel.Set(JsonConvert.SerializeObject(new LocMetaReader(asset), Formatting.Indented), mount + selected.ReaderEntry.Name);
|
|
break;
|
|
}
|
|
case ".locres":
|
|
{
|
|
using var asset = GetMemoryStream(selected.ReaderEntry.ContainerName, mount + selected.ReaderEntry.GetPathWithoutExtension());
|
|
asset.Position = 0;
|
|
AvalonEditVm.avalonEditViewModel.Set(JsonConvert.SerializeObject(new LocResReader(asset).Entries, Formatting.Indented), mount + selected.ReaderEntry.Name);
|
|
break;
|
|
}
|
|
case ".udic":
|
|
{
|
|
using var asset = GetMemoryStream(selected.ReaderEntry.ContainerName, mount + selected.ReaderEntry.GetPathWithoutExtension());
|
|
asset.Position = 0;
|
|
AvalonEditVm.avalonEditViewModel.Set(JsonConvert.SerializeObject(new FOodleDictionaryArchive(asset).Header, Formatting.Indented), mount + selected.ReaderEntry.Name);
|
|
break;
|
|
}
|
|
case ".bin":
|
|
{
|
|
if (
|
|
!selected.ReaderEntry.Name.Equals("FortniteGame/AssetRegistry.bin") && // this file is 85mb...
|
|
selected.ReaderEntry.Name.Contains("AssetRegistry")) // only parse AssetRegistry (basically the ones in dynamic paks)
|
|
{
|
|
using var asset = GetMemoryStream(selected.ReaderEntry.ContainerName, mount + selected.ReaderEntry.GetPathWithoutExtension());
|
|
asset.Position = 0;
|
|
AvalonEditVm.avalonEditViewModel.Set(JsonConvert.SerializeObject(new FAssetRegistryState(asset), Formatting.Indented), mount + selected.ReaderEntry.Name);
|
|
}
|
|
break;
|
|
}
|
|
case ".bnk":
|
|
case ".pck":
|
|
{
|
|
using var asset = GetMemoryStream(selected.ReaderEntry.ContainerName, mount + selected.ReaderEntry.GetPathWithoutExtension());
|
|
asset.Position = 0;
|
|
WwiseReader bnk = new WwiseReader(new BinaryReader(asset));
|
|
Application.Current.Dispatcher.Invoke(delegate
|
|
{
|
|
DebugHelper.WriteLine("{0} {1} {2}", "[FModel]", "[Window]", $"Opening Audio Player for {selected.ReaderEntry.GetNameWithExtension()}");
|
|
if (!FWindows.IsWindowOpen<Window>(Properties.Resources.AudioPlayer))
|
|
new AudioPlayer().LoadFiles(bnk.AudioFiles, mount + selected.ReaderEntry.GetPathWithoutFile());
|
|
else
|
|
((AudioPlayer)FWindows.GetOpenedWindow<Window>(Properties.Resources.AudioPlayer)).LoadFiles(bnk.AudioFiles, mount + selected.ReaderEntry.GetPathWithoutFile());
|
|
});
|
|
break;
|
|
}
|
|
case ".png":
|
|
{
|
|
using var asset = GetMemoryStream(selected.ReaderEntry.ContainerName, mount + selected.ReaderEntry.GetPathWithoutExtension());
|
|
asset.Position = 0;
|
|
ImageBoxVm.imageBoxViewModel.Set(SKBitmap.Decode(asset), mount + selected.ReaderEntry.Name);
|
|
break;
|
|
}
|
|
case ".ushaderbytecode":
|
|
break;
|
|
default:
|
|
AvalonEditVm.avalonEditViewModel.Set(GetJsonProperties(selected.ReaderEntry, mount, true), mount + selected.ReaderEntry.Name);
|
|
break;
|
|
}
|
|
|
|
if (Properties.Settings.Default.AutoExport)
|
|
Export(selected.ReaderEntry, true);
|
|
}
|
|
}
|
|
}
|
|
}).ContinueWith(t =>
|
|
{
|
|
_timer.Stop();
|
|
ExtractStopVm.stopViewModel.IsEnabled = false;
|
|
ExtractStopVm.extractViewModel.IsEnabled = true;
|
|
|
|
if (t.Exception != null) Tasks.TaskCompleted(t.Exception);
|
|
else StatusBarVm.statusBarViewModel.Set(string.Format(Properties.Resources.TimeElapsed, _timer.ElapsedMilliseconds), Properties.Resources.Success);
|
|
},
|
|
TaskScheduler.FromCurrentSynchronizationContext());
|
|
}
|
|
|
|
public static MemoryStream GetMemoryStream(string pakName, string pathWithoutExtension)
|
|
{
|
|
if (Globals.CachedPakFiles.TryGetValue(pakName, out PakFileReader pak))
|
|
{
|
|
if (pak.Initialized && !pak.TryGetFile(pathWithoutExtension, out ArraySegment<byte> uasset, out _, out _))
|
|
{
|
|
if (uasset != null)
|
|
{
|
|
return new MemoryStream(uasset.Array, uasset.Offset, uasset.Count);
|
|
}
|
|
}
|
|
} else if (Globals.CachedIoStores.TryGetValue(pakName, out var ioStore))
|
|
{
|
|
if (ioStore.IsInitialized && ioStore.TryGetFile(pathWithoutExtension, out ArraySegment<byte> uasset, out _, out _))
|
|
{
|
|
if (uasset != null)
|
|
{
|
|
return new MemoryStream(uasset.Array, uasset.Offset, uasset.Count);
|
|
}
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
public static string GetJsonProperties(ReaderEntry entry, string mount) => GetJsonProperties(entry, mount, false);
|
|
public static string GetJsonProperties(ReaderEntry entry, string mount, bool loadContent)
|
|
{
|
|
Package p = GetPackage(entry, mount, loadContent);
|
|
if (!p.Equals(default))
|
|
{
|
|
return p.JsonData;
|
|
}
|
|
return string.Empty;
|
|
}
|
|
|
|
public static Package GetPackage(ReaderEntry entry, string mount) => GetPackage(entry, mount, false);
|
|
public static Package GetPackage(ReaderEntry entry, string mount, bool loadContent)
|
|
{
|
|
TryGetPackage(entry, mount, out var p);
|
|
|
|
if (loadContent)
|
|
{
|
|
// Texture
|
|
var i = p.GetExport<UTexture2D>();
|
|
if (i != null)
|
|
{
|
|
ImageBoxVm.imageBoxViewModel.Set(i.Image, entry.GetNameWithExtension());
|
|
return p;
|
|
}
|
|
|
|
var ak = p.GetExport<UAkMediaAssetData>();
|
|
if (ak != null)
|
|
{
|
|
if (Properties.Settings.Default.AutoOpenSounds)
|
|
{
|
|
Application.Current.Dispatcher.Invoke(delegate
|
|
{
|
|
DebugHelper.WriteLine("{0} {1} {2}", "[FModel]", "[Window]", $"Opening Audio Player for {entry.GetNameWithExtension()}");
|
|
if (!FWindows.IsWindowOpen<Window>(Properties.Resources.AudioPlayer))
|
|
new AudioPlayer().LoadFile(ak.Sound, entry.GetNameWithoutExtension() + ".wem", mount + entry.GetPathWithoutFile());
|
|
else
|
|
((AudioPlayer)FWindows.GetOpenedWindow<Window>(Properties.Resources.AudioPlayer)).LoadFile(ak.Sound, entry.GetNameWithoutExtension() + ".wem", mount + entry.GetPathWithoutFile());
|
|
});
|
|
}
|
|
return p;
|
|
}
|
|
|
|
// Sound
|
|
var s = p.GetExport<USoundWave>();
|
|
if (s != null && (s.AudioFormat.String.Equals("OGG") || s.AudioFormat.String.Equals("OGG10000-1-1-1-1-1") || s.AudioFormat.String.Equals("OGG10025600-1-1-1-1-1")))
|
|
{
|
|
string path = Properties.Settings.Default.OutputPath + "\\Sounds\\" + mount + entry.GetPathWithoutExtension() + ".ogg";
|
|
Directory.CreateDirectory(Path.GetDirectoryName(path));
|
|
if (File.Exists(path))
|
|
{
|
|
if (!Paks.IsFileWriteLocked(new FileInfo(path))) // aka isn't already being played, rewrite it
|
|
{
|
|
using var stream = new FileStream(path, FileMode.Create, FileAccess.Write);
|
|
using var writer = new BinaryWriter(stream);
|
|
writer.Write(s.Sound);
|
|
writer.Flush();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
using var stream = new FileStream(path, FileMode.Create, FileAccess.Write);
|
|
using var writer = new BinaryWriter(stream);
|
|
writer.Write(s.Sound);
|
|
writer.Flush();
|
|
}
|
|
|
|
if (Properties.Settings.Default.AutoOpenSounds)
|
|
{
|
|
Application.Current.Dispatcher.Invoke(delegate
|
|
{
|
|
DebugHelper.WriteLine("{0} {1} {2}", "[FModel]", "[Window]", $"Opening Audio Player for {entry.GetNameWithExtension()}");
|
|
if (!FWindows.IsWindowOpen<Window>(Properties.Resources.AudioPlayer))
|
|
new AudioPlayer().LoadFile(path);
|
|
else
|
|
((AudioPlayer)FWindows.GetOpenedWindow<Window>(Properties.Resources.AudioPlayer)).LoadFile(path);
|
|
});
|
|
}
|
|
return p;
|
|
}
|
|
else if (s != null && (s.AudioFormat.String.Equals("OPUS") || s.AudioFormat.String.Equals("ADPCM")))
|
|
{
|
|
Application.Current.Dispatcher.Invoke(delegate
|
|
{
|
|
DebugHelper.WriteLine("{0} {1} {2}", "[FModel]", "[Window]", $"Opening Audio Player for {entry.GetNameWithExtension()}");
|
|
if (!FWindows.IsWindowOpen<Window>(Properties.Resources.AudioPlayer))
|
|
new AudioPlayer().LoadFiles(new Dictionary<string, byte[]>(1) {{ entry.GetNameWithoutExtension() + "." + s.AudioFormat.String.ToLowerInvariant(), s.Sound }}, entry.GetPathWithoutFile());
|
|
else
|
|
((AudioPlayer)FWindows.GetOpenedWindow<Window>(Properties.Resources.AudioPlayer)).LoadFiles(new Dictionary<string, byte[]>(1) { { entry.GetNameWithoutExtension() + "." + s.AudioFormat.String.ToLowerInvariant(), s.Sound } }, entry.GetPathWithoutFile());
|
|
});
|
|
}
|
|
else if (s != null)
|
|
{
|
|
string path = Properties.Settings.Default.OutputPath + "\\Sounds\\" + mount + entry.GetPathWithoutExtension() + "." + s.AudioFormat.String.ToLowerInvariant();
|
|
Directory.CreateDirectory(Path.GetDirectoryName(path));
|
|
using var stream = new FileStream(path, FileMode.Create, FileAccess.Write);
|
|
using var writer = new BinaryWriter(stream);
|
|
writer.Write(s.Sound);
|
|
writer.Flush();
|
|
return p;
|
|
}
|
|
|
|
// Image Creator
|
|
if (TryDrawIcon(entry.Name, p.ExportTypes, p.Exports))
|
|
return p;
|
|
}
|
|
|
|
return p;
|
|
}
|
|
private static bool TryGetPackage(ReaderEntry entry, string mount, out Package package)
|
|
{
|
|
DebugHelper.WriteLine("{0} {1} {2} {3}", "[FModel]", "[Assets]", "[Package]", $"Searching for '{mount + entry.Name}'s package");
|
|
if (_CachedFiles.TryGetValue(entry, out var dict))
|
|
{
|
|
package = dict.ElementAt(0).Key;
|
|
return true;
|
|
}
|
|
|
|
if (Globals.CachedPakFiles.TryGetValue(entry.ContainerName, out PakFileReader pak))
|
|
{
|
|
if (pak.Initialized && pak.TryGetFile(mount + entry.GetPathWithoutExtension(), out ArraySegment<byte> uasset, out ArraySegment<byte> uexp, out ArraySegment<byte> ubulk))
|
|
{
|
|
package = new PakPackage(uasset, uexp, ubulk);
|
|
_CachedFiles[entry] = new Dictionary<Package, ArraySegment<byte>[]>
|
|
{
|
|
[package] = new ArraySegment<byte>[] { uasset, uexp, ubulk }
|
|
};
|
|
return true;
|
|
}
|
|
}
|
|
else if (entry is FIoStoreEntry ioStoreEntry)
|
|
{
|
|
var uasset = ioStoreEntry.GetData();
|
|
var uexp = (ioStoreEntry.Uexp as FIoStoreEntry)?.GetData();
|
|
var ubulk = (ioStoreEntry.Ubulk as FIoStoreEntry)?.GetData();
|
|
if (uexp != null)
|
|
package = new PakPackage(uasset, uexp, ubulk);
|
|
else
|
|
package = new IoPackage(uasset, ubulk);
|
|
#if !DEBUG
|
|
_CachedFiles[entry] = new Dictionary<Package, ArraySegment<byte>[]>
|
|
{
|
|
[package] = new ArraySegment<byte>[] { uasset, uexp, ubulk }
|
|
};
|
|
#endif
|
|
|
|
return true;
|
|
}
|
|
|
|
DebugHelper.WriteLine("{0} {1} {2} {3}", "[FModel]", "[Assets]", "[Package]", $"No package found for '{mount + entry.Name}'");
|
|
package = default;
|
|
return false;
|
|
}
|
|
|
|
public static ArraySegment<byte>[] GetArraySegmentByte(ReaderEntry entry, string mount)
|
|
{
|
|
TryGetArraySegmentByte(entry, mount, out var b);
|
|
return b;
|
|
}
|
|
private static bool TryGetArraySegmentByte(ReaderEntry entry, string mount, out ArraySegment<byte>[] arraySegment)
|
|
{
|
|
DebugHelper.WriteLine("{0} {1} {2} {3}", "[FModel]", "[Assets]", "[ArraySegment]", $"Searching for '{mount + entry.Name}'s ArraySegment<byte>");
|
|
if (_CachedFiles.TryGetValue(entry, out var dict))
|
|
{
|
|
arraySegment = dict.ElementAt(0).Value;
|
|
return true;
|
|
}
|
|
|
|
if (Globals.CachedPakFiles.TryGetValue(entry.ContainerName, out PakFileReader pak))
|
|
{
|
|
if (pak.Initialized && pak.TryGetFile(mount + entry.GetPathWithoutExtension(), out ArraySegment<byte> uasset, out ArraySegment<byte> uexp, out ArraySegment<byte> ubulk))
|
|
{
|
|
arraySegment = new ArraySegment<byte>[] { uasset, uexp, ubulk };
|
|
return true;
|
|
}
|
|
} else if (entry is FIoStoreEntry ioStoreEntry)
|
|
{
|
|
var uasset = ioStoreEntry.GetData();
|
|
var uexp = (ioStoreEntry.Uexp as FIoStoreEntry)?.GetData();
|
|
var ubulk = (ioStoreEntry.Ubulk as FIoStoreEntry)?.GetData();
|
|
arraySegment = new ArraySegment<byte>[] { uasset, uexp, ubulk };
|
|
return true;
|
|
}
|
|
|
|
DebugHelper.WriteLine("{0} {1} {2} {3}", "[FModel]", "[Assets]", "[ArraySegment]", $"No ArraySegment<byte> found for '{mount + entry.Name}'");
|
|
arraySegment = default;
|
|
return false;
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static void Filter(string filter, string item, out bool bSearch)
|
|
{
|
|
if (filter.StartsWith("!="))
|
|
bSearch = item.IndexOf(filter[2..], StringComparison.CurrentCultureIgnoreCase) < 0;
|
|
else if (filter.StartsWith("=="))
|
|
bSearch = item.IndexOf(filter[2..], StringComparison.CurrentCulture) >= 0;
|
|
else
|
|
bSearch = item.IndexOf(filter, StringComparison.CurrentCultureIgnoreCase) >= 0;
|
|
}
|
|
|
|
public static void Export(ReaderEntry entry, bool autoSave)
|
|
{
|
|
switch (entry.GetExtension())
|
|
{
|
|
case ".uasset": // embedded data export
|
|
case ".umap": // embedded data export
|
|
{
|
|
FFileIoStoreReader io = null;
|
|
if (Globals.CachedPakFiles.TryGetValue(entry.ContainerName, out var r) || Globals.CachedIoStores.TryGetValue(entry.ContainerName, out io))
|
|
{
|
|
string mount = r != null ? r.MountPoint : io!.MountPoint;
|
|
if (TryGetArraySegmentByte(entry, mount, out var data))
|
|
{
|
|
string[] ext = string.Join(":", entry.GetExtension(), entry.Uexp?.GetExtension(), entry.Ubulk?.GetExtension()).Split(':');
|
|
for (int i = 0; i < data.Length; i++)
|
|
{
|
|
if (data[i] == null)
|
|
continue;
|
|
|
|
string basePath = Properties.Settings.Default.OutputPath + "\\Exports\\" + mount[1..];
|
|
string fullPath = basePath + Path.ChangeExtension(entry.Name, ext[i]);
|
|
string name = Path.GetFileName(fullPath);
|
|
Directory.CreateDirectory(basePath + entry.GetPathWithoutFile());
|
|
|
|
using var stream = new FileStream(fullPath, FileMode.Create, FileAccess.Write);
|
|
using var writer = new BinaryWriter(stream);
|
|
writer.Write(data[i]);
|
|
writer.Flush();
|
|
|
|
if (File.Exists(fullPath))
|
|
{
|
|
DebugHelper.WriteLine("{0} {1} {2}", "[FModel]", "[Assets]", $"{name} successfully exported");
|
|
if (autoSave)
|
|
FConsole.AppendText(string.Format(Properties.Resources.DataExported, name), FColors.Green, true);
|
|
else
|
|
Globals.gNotifier.ShowCustomMessage(Properties.Resources.Success, string.Format(Properties.Resources.DataExported, name), string.Empty, fullPath);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
default: // single data export
|
|
{
|
|
FFileIoStoreReader io = null;
|
|
if (Globals.CachedPakFiles.TryGetValue(entry.ContainerName, out var r) || Globals.CachedIoStores.TryGetValue(entry.ContainerName, out io))
|
|
{
|
|
string mount = r != null ? r.MountPoint : io!.MountPoint;
|
|
string basePath = Properties.Settings.Default.OutputPath + "\\Exports\\" + mount[1..];
|
|
string fullPath = basePath + entry.Name;
|
|
string name = Path.GetFileName(fullPath);
|
|
Directory.CreateDirectory(basePath + entry.GetPathWithoutFile());
|
|
|
|
using var data = GetMemoryStream(entry.ContainerName, mount + entry.GetPathWithoutExtension());
|
|
using var stream = new FileStream(fullPath, FileMode.Create, FileAccess.Write);
|
|
data.WriteTo(stream);
|
|
|
|
if (File.Exists(fullPath))
|
|
{
|
|
DebugHelper.WriteLine("{0} {1} {2}", "[FModel]", "[Assets]", $"{name} successfully exported");
|
|
if (autoSave)
|
|
FConsole.AppendText(string.Format(Properties.Resources.DataExported, name), FColors.Green, true);
|
|
else
|
|
Globals.gNotifier.ShowCustomMessage(Properties.Resources.Success, string.Format(Properties.Resources.DataExported, name, string.Empty, fullPath));
|
|
}
|
|
} else {}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
public static void Copy(IList entries, ECopy mode)
|
|
{
|
|
StringBuilder sb = new StringBuilder();
|
|
if (entries[0] is ListBoxViewModel)
|
|
{
|
|
foreach (ListBoxViewModel selectedItem in entries)
|
|
{
|
|
sb.AppendLine(Copy(selectedItem.ReaderEntry, mode));
|
|
}
|
|
}
|
|
else if (entries[0] is DataGridViewModel)
|
|
{
|
|
foreach (DataGridViewModel selectedItem in entries)
|
|
{
|
|
sb.AppendLine(Copy(selectedItem.Name, mode));
|
|
}
|
|
}
|
|
Copy(sb.ToString().Trim());
|
|
}
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static string Copy(ReaderEntry entry, ECopy mode)
|
|
{
|
|
FFileIoStoreReader io = null;
|
|
if (Globals.CachedPakFiles.TryGetValue(entry.ContainerName, out var r) || Globals.CachedIoStores.TryGetValue(entry.ContainerName, out io))
|
|
{
|
|
string toCopy;
|
|
if (r != null)
|
|
toCopy = r.MountPoint.Substring(1);
|
|
else
|
|
toCopy = io!.MountPoint[1..];
|
|
if (mode == ECopy.Path)
|
|
toCopy += entry.Name;
|
|
else if (mode == ECopy.PathNoExt)
|
|
toCopy += entry.GetPathWithoutExtension();
|
|
else if (mode == ECopy.PathNoFile)
|
|
toCopy += entry.GetPathWithoutFile();
|
|
else if (mode == ECopy.File)
|
|
toCopy = entry.GetNameWithExtension();
|
|
else if (mode == ECopy.FileNoExt)
|
|
toCopy = entry.GetNameWithoutExtension();
|
|
return toCopy;
|
|
}
|
|
return string.Empty;
|
|
}
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static string Copy(string fullPath, ECopy mode)
|
|
{
|
|
string toCopy = string.Empty;
|
|
if (mode == ECopy.Path)
|
|
toCopy = fullPath;
|
|
else if (mode == ECopy.PathNoExt)
|
|
toCopy = fullPath.Substring(0, fullPath.LastIndexOf("."));
|
|
else if (mode == ECopy.PathNoFile)
|
|
toCopy = fullPath.Substring(0, fullPath.LastIndexOf("/") + 1);
|
|
else if (mode == ECopy.File)
|
|
toCopy = fullPath.Substring(fullPath.LastIndexOf("/") + 1);
|
|
else if (mode == ECopy.FileNoExt)
|
|
toCopy = fullPath.Substring(fullPath.LastIndexOf("/") + 1, fullPath.LastIndexOf(".") - (fullPath.LastIndexOf("/") + 1));
|
|
return toCopy;
|
|
}
|
|
public static void Copy(string toCopy)
|
|
{
|
|
Clipboard.SetText(toCopy);
|
|
if (Clipboard.GetText().Equals(toCopy))
|
|
Globals.gNotifier.ShowCustomMessage(Properties.Resources.Success, Properties.Resources.CopySuccess, "/FModel;component/Resources/check-circle.ico");
|
|
}
|
|
}
|
|
}
|