mirror of
https://github.com/4sval/FModel.git
synced 2026-03-22 01:34:37 -05:00
544 lines
24 KiB
C#
544 lines
24 KiB
C#
using FModel.Methods.SyntaxHighlighter;
|
|
using Microsoft.Win32;
|
|
using Newtonsoft.Json;
|
|
using Newtonsoft.Json.Linq;
|
|
using PakReader;
|
|
using SkiaSharp;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Windows.Media;
|
|
using System.Windows.Media.Imaging;
|
|
using FProp = FModel.Properties.Settings;
|
|
|
|
namespace FModel.Methods.Utilities
|
|
{
|
|
static class AssetsUtility
|
|
{
|
|
public static string GetAssetPathToCopy(bool isName = false, bool withExtension = true)
|
|
{
|
|
string treePath = TreeViewUtility.GetFullPath(FWindow.TVItem);
|
|
string path = treePath + "/" + FWindow.FCurrentAsset;
|
|
|
|
path = path.Contains(".") ? path : path + ".uasset";
|
|
|
|
if (isName) { path = Path.GetFileName(path); }
|
|
|
|
if (!withExtension) { path = isName ? Path.GetFileNameWithoutExtension(path) : FoldersUtility.GetFullPathWithoutExtension(path); }
|
|
if (path.StartsWith("/")) { path = path.Substring(1); }
|
|
|
|
new UpdateMyConsole(path, CColors.Blue).Append();
|
|
new UpdateMyConsole(" Copied!", CColors.White, true).Append();
|
|
return path;
|
|
|
|
}
|
|
|
|
public static string GetReadableSize(long size)
|
|
{
|
|
long absolute_i = size < 0 ? -size : size;
|
|
string suffix;
|
|
double readable;
|
|
if (absolute_i >= 0x40000000)
|
|
{
|
|
suffix = "GB";
|
|
readable = size >> 20;
|
|
}
|
|
else if (absolute_i >= 0x100000)
|
|
{
|
|
suffix = "MB";
|
|
readable = size >> 10;
|
|
}
|
|
else if (absolute_i >= 0x400)
|
|
{
|
|
suffix = "KB";
|
|
readable = size;
|
|
}
|
|
else
|
|
{
|
|
return size.ToString("0 B");
|
|
}
|
|
readable = readable / 1024;
|
|
return readable.ToString("0.## ") + suffix;
|
|
}
|
|
|
|
public static PakReader.PakReader GetPakReader(string assetPath)
|
|
{
|
|
string trigger = Path.HasExtension(assetPath) ? assetPath : assetPath + ".uasset";
|
|
if (AssetEntries.AssetEntriesDict.ContainsKey(trigger))
|
|
{
|
|
return AssetEntries.AssetEntriesDict[trigger];
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/// <summary>
|
|
/// goes from all files in a pak -> to only the ones (uasset, uexp, ubulk) we need to loop to get an asset data
|
|
/// it's ugly but way better than before when it's about time
|
|
/// </summary>
|
|
/// <param name="assetPath"></param>
|
|
/// <returns></returns>
|
|
public static List<FPakEntry> GetPakEntries(string assetPath)
|
|
{
|
|
if (Path.HasExtension(assetPath))
|
|
{
|
|
if (AssetEntries.ArraySearcher.ContainsKey(assetPath))
|
|
{
|
|
return AssetEntries.ArraySearcher[assetPath].Where(x => x.Name == assetPath).Select(x => x).ToList<FPakEntry>();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
List<FPakEntry> toReturn = new List<FPakEntry>();
|
|
if (AssetEntries.ArraySearcher.ContainsKey(assetPath + ".uasset"))
|
|
{
|
|
toReturn.Add(AssetEntries.ArraySearcher[assetPath + ".uasset"].Where(x => x.Name == assetPath + ".uasset").Select(x => x).FirstOrDefault());
|
|
}
|
|
if (AssetEntries.ArraySearcher.ContainsKey(assetPath + ".uexp"))
|
|
{
|
|
toReturn.Add(AssetEntries.ArraySearcher[assetPath + ".uexp"].Where(x => x.Name == assetPath + ".uexp").Select(x => x).FirstOrDefault());
|
|
}
|
|
if (AssetEntries.ArraySearcher.ContainsKey(assetPath + ".ubulk"))
|
|
{
|
|
toReturn.Add(AssetEntries.ArraySearcher[assetPath + ".ubulk"].Where(x => x.Name == assetPath + ".ubulk").Select(x => x).FirstOrDefault());
|
|
}
|
|
return toReturn;
|
|
}
|
|
return new List<FPakEntry>();
|
|
}
|
|
|
|
public static AssetReader GetAssetReader(Stream[] AssetStreamList)
|
|
{
|
|
if (AssetStreamList[0] != null && AssetStreamList.Length >= 2 && AssetStreamList.Length <= 3)
|
|
{
|
|
return new AssetReader(AssetStreamList[0], AssetStreamList[1], AssetStreamList[2] != null ? AssetStreamList[2]: null); //UASSET -> UEXP -> UBULK IF EXIST
|
|
}
|
|
else { return null; }
|
|
}
|
|
|
|
public static string GetAssetJsonData(PakReader.PakReader reader, IEnumerable<FPakEntry> entriesList, bool loadImageInBox = false)
|
|
{
|
|
DebugHelper.WriteLine("Assets: Gathering info about {0}", entriesList.ElementAt(0).Name);
|
|
|
|
Stream[] AssetStreamArray = new Stream[3];
|
|
|
|
foreach (FPakEntry entry in entriesList)
|
|
{
|
|
#region AUTO EXTRACT RAW
|
|
if (FProp.Default.FAutoExtractRaw)
|
|
{
|
|
string path = FProp.Default.FOutput_Path + "\\Exports\\" + entry.Name;
|
|
string pWExt = FoldersUtility.GetFullPathWithoutExtension(entry.Name);
|
|
string subfolders = pWExt.Substring(0, pWExt.LastIndexOf("/", StringComparison.InvariantCultureIgnoreCase));
|
|
|
|
Directory.CreateDirectory(FProp.Default.FOutput_Path + "\\Exports\\" + subfolders);
|
|
Stream stream = reader.GetPackageStream(entry);
|
|
using (var fStream = File.OpenWrite(path))
|
|
using (stream)
|
|
{
|
|
stream.CopyTo(fStream);
|
|
}
|
|
|
|
if (File.Exists(path))
|
|
{
|
|
DebugHelper.WriteLine("Assets: Successfully extracted data of {0}", entry.Name);
|
|
|
|
new UpdateMyConsole(Path.GetFileName(path), CColors.Blue).Append();
|
|
new UpdateMyConsole(" successfully exported", CColors.White, true).Append();
|
|
}
|
|
else //just in case
|
|
{
|
|
DebugHelper.WriteLine("Assets: Couldn't extract data of {0}", entry.Name);
|
|
|
|
new UpdateMyConsole("Bruh moment\nCouldn't export ", CColors.White).Append();
|
|
new UpdateMyConsole(Path.GetFileName(path), CColors.Blue, true).Append();
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
switch (Path.GetExtension(entry.Name.ToLowerInvariant()))
|
|
{
|
|
case ".ini":
|
|
FWindow.FMain.Dispatcher.InvokeAsync(() =>
|
|
{
|
|
FWindow.FMain.AssetPropertiesBox_Main.SyntaxHighlighting = ResourceLoader.LoadHighlightingDefinition("Ini.xshd");
|
|
});
|
|
using (var s = reader.GetPackageStream(entry))
|
|
using (var r = new StreamReader(s))
|
|
return r.ReadToEnd();
|
|
case ".uproject":
|
|
case ".uplugin":
|
|
case ".upluginmanifest":
|
|
using (var s = reader.GetPackageStream(entry))
|
|
using (var r = new StreamReader(s))
|
|
return r.ReadToEnd();
|
|
case ".locmeta":
|
|
using (var s = reader.GetPackageStream(entry))
|
|
return JsonConvert.SerializeObject(new LocMetaFile(s), Formatting.Indented);
|
|
case ".locres":
|
|
using (var s = reader.GetPackageStream(entry))
|
|
return JsonConvert.SerializeObject(new LocResFile(s).Entries, Formatting.Indented);
|
|
case ".udic":
|
|
using (var s = reader.GetPackageStream(entry))
|
|
using (var r = new BinaryReader(s))
|
|
return JsonConvert.SerializeObject(new UDicFile(r).Header, Formatting.Indented);
|
|
case ".bin":
|
|
if (string.Equals(entry.Name, "/FortniteGame/AssetRegistry.bin") || !entry.Name.Contains("AssetRegistry")) //MEMORY ISSUE
|
|
{
|
|
break;
|
|
}
|
|
|
|
using (var s = reader.GetPackageStream(entry))
|
|
return JsonConvert.SerializeObject(new AssetRegistryFile(s), Formatting.Indented);
|
|
default:
|
|
if (entry.Name.EndsWith(".uasset")) { AssetStreamArray[0] = reader.GetPackageStream(entry); }
|
|
|
|
if (entry.Name.EndsWith(".uexp")) { AssetStreamArray[1] = reader.GetPackageStream(entry); }
|
|
|
|
if (entry.Name.EndsWith(".ubulk")) { AssetStreamArray[2] = reader.GetPackageStream(entry); }
|
|
break;
|
|
}
|
|
}
|
|
|
|
AssetReader ar = GetAssetReader(AssetStreamArray);
|
|
if (ar != null)
|
|
{
|
|
if (loadImageInBox)
|
|
{
|
|
foreach (ExportObject eo in ar.Exports)
|
|
{
|
|
switch (eo)
|
|
{
|
|
case Texture2D texture:
|
|
SKImage image = texture.GetImage();
|
|
if (image != null)
|
|
{
|
|
using (var data = image.Encode())
|
|
using (var stream = data.AsStream())
|
|
{
|
|
ImageSource img = ImagesUtility.GetImageSource(stream);
|
|
FWindow.FMain.Dispatcher.InvokeAsync(() =>
|
|
{
|
|
FWindow.FMain.ImageBox_Main.Source = BitmapFrame.Create((BitmapSource)img); //thread safe and fast af
|
|
|
|
if (FWindow.FMain.MI_Auto_Save_Images.IsChecked) //auto save images
|
|
{
|
|
ImagesUtility.SaveImage(FProp.Default.FOutput_Path + "\\Icons\\" + FWindow.FCurrentAsset + ".png");
|
|
}
|
|
});
|
|
}
|
|
}
|
|
return JsonConvert.SerializeObject(texture.textures, Formatting.Indented);
|
|
case USoundWave sound:
|
|
using (sound)
|
|
{
|
|
byte[] s = readSound(sound);
|
|
if (s != null)
|
|
{
|
|
string path = FProp.Default.FOutput_Path + "\\Sounds\\" + FWindow.FCurrentAsset + ".ogg";
|
|
File.WriteAllBytes(path, s);
|
|
|
|
//open sound
|
|
if (FProp.Default.FOpenSounds)
|
|
{
|
|
FoldersUtility.OpenWithDefaultProgram(path);
|
|
}
|
|
}
|
|
|
|
GC.Collect();
|
|
GC.WaitForPendingFinalizers();
|
|
return JsonConvert.SerializeObject(sound.base_object, Formatting.Indented);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
string stringData = JsonConvert.SerializeObject(ar.Exports, Formatting.Indented);
|
|
|
|
#region AUTO SAVE JSON
|
|
if (FProp.Default.FAutoSaveJson)
|
|
{
|
|
string name = Path.GetFileNameWithoutExtension(entriesList.ElementAt(0).Name);
|
|
string path = FProp.Default.FOutput_Path + "\\JSONs\\" + name + ".json";
|
|
if (!string.IsNullOrEmpty(stringData))
|
|
{
|
|
File.WriteAllText(path, stringData);
|
|
if (File.Exists(path))
|
|
{
|
|
DebugHelper.WriteLine("Assets: Successfully saved serialized data of {0}", entriesList.ElementAt(0).Name);
|
|
|
|
new UpdateMyConsole(name, CColors.Blue).Append();
|
|
new UpdateMyConsole("'s Json data successfully saved", CColors.White, true).Append();
|
|
}
|
|
else //just in case
|
|
{
|
|
DebugHelper.WriteLine("Assets: Couldn't save serialized data of {0}", entriesList.ElementAt(0).Name);
|
|
|
|
new UpdateMyConsole("Bruh moment\nCouldn't export ", CColors.White).Append();
|
|
new UpdateMyConsole(name, CColors.Blue, true).Append();
|
|
}
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
return stringData;
|
|
}
|
|
|
|
return string.Empty;
|
|
}
|
|
|
|
public static string GetAssetJsonDataByPath(string path, bool loadImageInBox = false, string pathEntries = null)
|
|
{
|
|
string jsonData = null;
|
|
PakReader.PakReader reader = GetPakReader(path);
|
|
if (reader != null)
|
|
{
|
|
List<FPakEntry> entriesList = GetPakEntries(pathEntries != null ? pathEntries : path);
|
|
if (entriesList != null)
|
|
jsonData = GetAssetJsonData(reader, entriesList, loadImageInBox);
|
|
else
|
|
DebugHelper.WriteLine("Assets: GetAssetJsonDataByPath -> entriesList -> is empty for {0}", path);
|
|
}
|
|
else
|
|
DebugHelper.WriteLine("Assets: No PakReader found for {0}", path);
|
|
|
|
return jsonData;
|
|
}
|
|
|
|
public static byte[] readSound(USoundWave sound)
|
|
{
|
|
if (!sound.bStreaming)
|
|
{
|
|
if (sound.bCooked && sound.compressedFormatData.Count > 0)
|
|
{
|
|
FSoundFormatData data = sound.compressedFormatData[0];
|
|
return data.data.data;
|
|
}
|
|
else if(sound.rawData.data != null)
|
|
{
|
|
return sound.rawData.data;
|
|
}
|
|
}
|
|
else if (sound.bStreaming && sound.streamedAudioChunks != null && !string.IsNullOrEmpty(sound.format))
|
|
{
|
|
List<byte> bytes = new List<byte>();
|
|
foreach (FStreamedAudioChunk chunk in sound.streamedAudioChunks)
|
|
{
|
|
chunk.data.data.ToList().ForEach(x => bytes.Add(x));
|
|
}
|
|
return bytes.ToArray();
|
|
}
|
|
return new byte[0];
|
|
}
|
|
|
|
public static Stream GetStreamImageFromPath(string AssetFullPath)
|
|
{
|
|
PakReader.PakReader reader = GetPakReader(AssetFullPath);
|
|
if (reader != null)
|
|
{
|
|
List<FPakEntry> entriesList = GetPakEntries(AssetFullPath);
|
|
Stream[] AssetStreamArray = new Stream[3];
|
|
foreach (FPakEntry entry in entriesList)
|
|
{
|
|
switch (Path.GetExtension(entry.Name.ToLowerInvariant()))
|
|
{
|
|
case ".ini":
|
|
break;
|
|
case ".uproject":
|
|
case ".uplugin":
|
|
case ".upluginmanifest":
|
|
break;
|
|
case ".locmeta":
|
|
break;
|
|
case ".locres":
|
|
break;
|
|
case ".udic":
|
|
break;
|
|
case ".bin":
|
|
break;
|
|
default:
|
|
if (entry.Name.EndsWith(".uasset")) { AssetStreamArray[0] = reader.GetPackageStream(entry); }
|
|
|
|
if (entry.Name.EndsWith(".uexp")) { AssetStreamArray[1] = reader.GetPackageStream(entry); }
|
|
|
|
if (entry.Name.EndsWith(".ubulk")) { AssetStreamArray[2] = reader.GetPackageStream(entry); }
|
|
break;
|
|
}
|
|
}
|
|
|
|
AssetReader ar = GetAssetReader(AssetStreamArray);
|
|
if (ar != null)
|
|
{
|
|
ExportObject eo = ar.Exports.FirstOrDefault(x => x is Texture2D);
|
|
if (eo != null)
|
|
{
|
|
SKImage image = ((Texture2D)eo).GetImage();
|
|
if (image != null)
|
|
{
|
|
return image.Encode().AsStream();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public static void ExportAssetData(string fPath = null)
|
|
{
|
|
string fullPath = fPath == null ? TreeViewUtility.GetFullPath(FWindow.TVItem) + "/" + FWindow.FCurrentAsset : fPath;
|
|
PakReader.PakReader reader = GetPakReader(fullPath);
|
|
if (reader != null)
|
|
{
|
|
List<FPakEntry> entriesList = GetPakEntries(fullPath);
|
|
foreach (FPakEntry entry in entriesList)
|
|
{
|
|
string path = FProp.Default.FOutput_Path + "\\Exports\\" + entry.Name;
|
|
string pWExt = FoldersUtility.GetFullPathWithoutExtension(entry.Name);
|
|
string subfolders = pWExt.Substring(0, pWExt.LastIndexOf("/", StringComparison.InvariantCultureIgnoreCase));
|
|
|
|
Directory.CreateDirectory(FProp.Default.FOutput_Path + "\\Exports\\" + subfolders);
|
|
Stream stream = reader.GetPackageStream(entry);
|
|
using (var fStream = File.OpenWrite(path))
|
|
using (stream)
|
|
{
|
|
stream.CopyTo(fStream);
|
|
}
|
|
|
|
if (File.Exists(path))
|
|
{
|
|
DebugHelper.WriteLine("ExportAssetData: Successfully extracted data of {0}", entry.Name);
|
|
|
|
new UpdateMyConsole(Path.GetFileName(path), CColors.Blue).Append();
|
|
new UpdateMyConsole(" successfully exported", CColors.White, true).Append();
|
|
}
|
|
else //just in case
|
|
{
|
|
DebugHelper.WriteLine("ExportAssetData: Couldn't extract data of {0}", entry.Name);
|
|
|
|
new UpdateMyConsole("Bruh moment\nCouldn't export ", CColors.White).Append();
|
|
new UpdateMyConsole(Path.GetFileName(path), CColors.Blue, true).Append();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public static void SaveAssetProperties()
|
|
{
|
|
string prop = FWindow.FMain.AssetPropertiesBox_Main.Text;
|
|
if (!string.IsNullOrEmpty(prop))
|
|
{
|
|
SaveFileDialog saveFileDialog = new SaveFileDialog();
|
|
saveFileDialog.Title = "Save Asset Properties";
|
|
saveFileDialog.FileName = FWindow.FCurrentAsset;
|
|
saveFileDialog.InitialDirectory = FProp.Default.FOutput_Path + "\\JSONs\\";
|
|
saveFileDialog.Filter = "JSON Files (*.json)|*.json";
|
|
if (saveFileDialog.ShowDialog() == true)
|
|
{
|
|
string path = saveFileDialog.FileName;
|
|
File.WriteAllText(path, prop);
|
|
if (File.Exists(path))
|
|
{
|
|
DebugHelper.WriteLine("SaveAssetProperties: Successfully saved serialized data of {0}", FWindow.FCurrentAsset);
|
|
|
|
new UpdateMyConsole(FWindow.FCurrentAsset, CColors.Blue).Append();
|
|
new UpdateMyConsole("'s Json data successfully saved", CColors.White, true).Append();
|
|
}
|
|
else //just in case
|
|
{
|
|
DebugHelper.WriteLine("SaveAssetProperties: Couldn't save serialized data of {0}", FWindow.FCurrentAsset);
|
|
|
|
new UpdateMyConsole("Bruh moment\nCouldn't export ", CColors.White).Append();
|
|
new UpdateMyConsole(FWindow.FCurrentAsset, CColors.Blue, true).Append();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public static bool IsValidJson(string strInput)
|
|
{
|
|
if (string.IsNullOrEmpty(strInput))
|
|
return false;
|
|
|
|
strInput = strInput.Trim();
|
|
if ((strInput.StartsWith("{") && strInput.EndsWith("}")) || //For object
|
|
(strInput.StartsWith("[") && strInput.EndsWith("]"))) //For array
|
|
{
|
|
try
|
|
{
|
|
JToken.Parse(strInput);
|
|
return true;
|
|
}
|
|
catch (Exception)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public static JToken ConvertJson2Token(string json)
|
|
{
|
|
dynamic AssetData = JsonConvert.DeserializeObject(json);
|
|
JToken AssetMainToken = null;
|
|
if (json.StartsWith("[") && json.EndsWith("]"))
|
|
{
|
|
JArray AssetArray = JArray.FromObject(AssetData);
|
|
AssetMainToken = AssetArray.Count() > 0 ? AssetArray[0] : null;
|
|
}
|
|
else if (json.StartsWith("{") && json.EndsWith("}"))
|
|
{
|
|
AssetMainToken = AssetData;
|
|
}
|
|
|
|
return AssetMainToken != null && !string.IsNullOrEmpty(AssetMainToken.ToString()) ? AssetMainToken : null;
|
|
}
|
|
|
|
public static T GetPropertyTag<T>(JArray properties, string name)
|
|
{
|
|
return properties
|
|
.Where(x => string.Equals(x["name"].Value<string>(), name))
|
|
.Select(x => x["tag_data"].Value<T>())
|
|
.FirstOrDefault();
|
|
}
|
|
public static T GetPropertyTagImport<T>(JArray properties, string name)
|
|
{
|
|
return properties
|
|
.Where(x => string.Equals(x["name"].Value<string>(), name))
|
|
.Select(x => x["tag_data"]["import"].Value<T>())
|
|
.FirstOrDefault();
|
|
}
|
|
public static T GetPropertyTagOuterImport<T>(JArray properties, string name)
|
|
{
|
|
return properties
|
|
.Where(x => string.Equals(x["name"].Value<string>(), name))
|
|
.Select(x => x["tag_data"]["outer_import"].Value<T>())
|
|
.FirstOrDefault();
|
|
}
|
|
public static T GetPropertyTagText<T>(JArray properties, string name, string tag_data)
|
|
{
|
|
return properties
|
|
.Where(x => string.Equals(x["name"].Value<string>(), name))
|
|
.Select(x => x["tag_data"][tag_data].Value<T>())
|
|
.FirstOrDefault();
|
|
}
|
|
public static T GetPropertyTagStruct<T>(JArray properties, string name, string struct_type)
|
|
{
|
|
return properties
|
|
.Where(x => string.Equals(x["name"].Value<string>(), name))
|
|
.Select(x => x["tag_data"]["struct_type"][struct_type].Value<T>())
|
|
.FirstOrDefault();
|
|
}
|
|
public static T GetPropertyTagItemData<T>(JArray properties, string item, string item_data)
|
|
{
|
|
return properties
|
|
.Where(x => string.Equals(x["Item1"].Value<string>(), item, StringComparison.InvariantCultureIgnoreCase))
|
|
.Select(x => x["Item2"][item_data].Value<T>())
|
|
.FirstOrDefault();
|
|
}
|
|
}
|
|
}
|