because someone was flexing

This commit is contained in:
Asval 2019-10-31 17:43:03 +01:00
parent 3901588270
commit 92ab3521ca
97 changed files with 3718 additions and 3140 deletions

View File

@ -82,6 +82,9 @@
<setting name="ReloadAES" serializeAs="String">
<value>True</value>
</setting>
<setting name="FOpenSounds" serializeAs="String">
<value>True</value>
</setting>
</FModel.Properties.Settings>
</userSettings>
<runtime>

View File

@ -233,10 +233,74 @@
<Compile Include="Methods\FVar.cs" />
<Compile Include="Methods\MessageBox\DarkMessageBox.cs" />
<Compile Include="Methods\PakReader\AESDecryptor.cs" />
<Compile Include="Methods\PakReader\AssetReader.cs" />
<Compile Include="Methods\PakReader\AssetRegReader.cs" />
<Compile Include="Methods\PakReader\ExportObject\AssetReader.cs" />
<Compile Include="Methods\PakReader\ExportObject\ExportObject.cs" />
<Compile Include="Methods\PakReader\ExportObject\UScript\UScriptStruct\FObjectExport.cs" />
<Compile Include="Methods\PakReader\ExportObject\UScript\UScriptStruct\FPackageIndex.cs" />
<Compile Include="Methods\PakReader\DDSDecoder.cs" />
<Compile Include="Methods\PakReader\ExportObject\UScript\UScriptStruct\FAnimKeyHeader.cs" />
<Compile Include="Methods\PakReader\ExportObject\UScript\UScriptStruct\FCompressedOffsetData.cs" />
<Compile Include="Methods\PakReader\ExportObject\UScript\UScriptStruct\FCompressedSegment.cs" />
<Compile Include="Methods\PakReader\ExportObject\UScript\UScriptArray.cs" />
<Compile Include="Methods\PakReader\ExportObject\UScript\UScriptMap.cs" />
<Compile Include="Methods\PakReader\ExportObject\UScript\UScriptStruct\FDateTime.cs" />
<Compile Include="Methods\PakReader\ExportObject\UScript\UScriptStruct\FLevelSequenceObjectReferenceMap\FLevelSequenceLegacyObjectReference.cs" />
<Compile Include="Methods\PakReader\ExportObject\UScript\UScriptStruct\FLevelSequenceObjectReferenceMap\FLevelSequenceObjectReferenceMap.cs" />
<Compile Include="Methods\PakReader\ExportObject\UScript\UScriptStruct\FRichCurveKey.cs" />
<Compile Include="Methods\PakReader\ExportObject\UScript\UScriptStruct\FScriptDelegate.cs" />
<Compile Include="Methods\PakReader\ExportObject\UScript\UScriptStruct\FSimpleCurveKey.cs" />
<Compile Include="Methods\PakReader\ExportObject\UScript\UScriptStruct\FSmartName.cs" />
<Compile Include="Methods\PakReader\ExportObject\UScript\UScriptStruct\FTrack.cs" />
<Compile Include="Methods\PakReader\ExportObject\UAnimSequence\UAnimSequence.cs" />
<Compile Include="Methods\PakReader\ExportObject\UScript\UScriptStruct\FPropertyTag\FPropertyTag.cs" />
<Compile Include="Methods\PakReader\ExportObject\UScript\UScriptStruct\FPropertyTag\FPropertyTagType.cs" />
<Compile Include="Methods\PakReader\ExportObject\UObject\UObject.cs" />
<Compile Include="Methods\PakReader\ExportObject\UScript\UScriptStruct\FColor.cs" />
<Compile Include="Methods\PakReader\ExportObject\UScript\UScriptStruct\FGameplayTagContainer.cs" />
<Compile Include="Methods\PakReader\ExportObject\UScript\UScriptStruct\FGuid.cs" />
<Compile Include="Methods\PakReader\ExportObject\UScript\UScriptStruct\FIntPoint.cs" />
<Compile Include="Methods\PakReader\ExportObject\UScript\UScriptStruct\FLinearColor.cs" />
<Compile Include="Methods\PakReader\ExportObject\UScript\UScriptStruct\FSoftObjectPath.cs" />
<Compile Include="Methods\PakReader\ExportObject\UScript\UScriptStruct\FSoftObjectPathMap.cs" />
<Compile Include="Methods\PakReader\ExportObject\UScript\UScriptStruct\FStructFallback.cs" />
<Compile Include="Methods\PakReader\ExportObject\UScript\UScriptStruct\FText.cs" />
<Compile Include="Methods\PakReader\ExportObject\UScript\UScriptStruct\FVector2D.cs" />
<Compile Include="Methods\PakReader\ExportObject\UScript\UScriptStruct\UScriptStruct.cs" />
<Compile Include="Methods\PakReader\ExportObject\UScript\UScriptStruct\FQuat.cs" />
<Compile Include="Methods\PakReader\ExportObject\UScript\UScriptStruct\FRotator.cs" />
<Compile Include="Methods\PakReader\ExportObject\UScript\UScriptStruct\FSkeletalMeshLODInfo.cs" />
<Compile Include="Methods\PakReader\ExportObject\UScript\UScriptStruct\FStaticLODModel\FColorVertexBuffer.cs" />
<Compile Include="Methods\PakReader\ExportObject\UScript\UScriptStruct\FStaticLODModel\FMultisizeIndexContainer.cs" />
<Compile Include="Methods\PakReader\ExportObject\UScript\UScriptStruct\FStaticLODModel\FPositionVertexBuffer.cs" />
<Compile Include="Methods\PakReader\ExportObject\UScript\UScriptStruct\FStaticLODModel\FSkeletalMeshVertexBuffer\FGPUVert4\FGPUVert4Float.cs" />
<Compile Include="Methods\PakReader\ExportObject\UScript\UScriptStruct\FStaticLODModel\FSkeletalMeshVertexBuffer\FGPUVert4\FGPUVert4Half.cs" />
<Compile Include="Methods\PakReader\ExportObject\UScript\UScriptStruct\FStaticLODModel\FSkeletalMeshVertexBuffer\FGPUVert4\FMeshUV\FMeshUVFloat.cs" />
<Compile Include="Methods\PakReader\ExportObject\UScript\UScriptStruct\FStaticLODModel\FSkeletalMeshVertexBuffer\FGPUVert4\FMeshUV\FMeshUVHalf.cs" />
<Compile Include="Methods\PakReader\ExportObject\UScript\UScriptStruct\FStaticLODModel\FSkeletalMeshVertexBuffer\FGPUVert4\FPackedNormal.cs" />
<Compile Include="Methods\PakReader\ExportObject\UScript\UScriptStruct\FStaticLODModel\FSkinWeightVertexBuffer\FSkinWeightInfo.cs" />
<Compile Include="Methods\PakReader\ExportObject\UScript\UScriptStruct\FStaticLODModel\FSkinWeightVertexBuffer\FSkinWeightVertexBuffer.cs" />
<Compile Include="Methods\PakReader\ExportObject\UScript\UScriptStruct\FStaticLODModel\FStaticMeshVertexBuffer\FStaticMeshUVItem4\FPackedRGBA16N.cs" />
<Compile Include="Methods\PakReader\ExportObject\UScript\UScriptStruct\FStaticLODModel\FStaticMeshVertexBuffer\FStaticMeshUVItem4\FStaticMeshUVItem4.cs" />
<Compile Include="Methods\PakReader\ExportObject\UScript\UScriptStruct\FStaticLODModel\FSkeletalMeshVertexBuffer\FSkeletalMeshVertexBuffer.cs" />
<Compile Include="Methods\PakReader\ExportObject\UScript\UScriptStruct\FStaticLODModel\FSkeletalMeshVertexClothBuffer.cs" />
<Compile Include="Methods\PakReader\ExportObject\UScript\UScriptStruct\FStaticLODModel\FSkinWeightProfilesData\FRuntimeSkinWeightProfileData\FRuntimeSkinWeightProfileData.cs" />
<Compile Include="Methods\PakReader\ExportObject\UScript\UScriptStruct\FStaticLODModel\FSkinWeightProfilesData\FRuntimeSkinWeightProfileData\FSkinWeightOverrideInfo.cs" />
<Compile Include="Methods\PakReader\ExportObject\UScript\UScriptStruct\FStaticLODModel\FSkinWeightProfilesData\FSkinWeightProfilesData.cs" />
<Compile Include="Methods\PakReader\ExportObject\UScript\UScriptStruct\FStaticLODModel\FStaticMeshVertexBuffer\FStaticMeshVertexBuffer.cs" />
<Compile Include="Methods\PakReader\ExportObject\UScript\UScriptStruct\FVector.cs" />
<Compile Include="Methods\PakReader\ExportObject\UScript\UScriptStruct\FReferencePose.cs" />
<Compile Include="Methods\PakReader\ExportObject\USkeleton\USkeleton.cs" />
<Compile Include="Methods\PakReader\ExportObject\UScript\UScriptStruct\FSoundFormatData.cs" />
<Compile Include="Methods\PakReader\ExportObject\UScript\UScriptStruct\FStreamedAudioChunk.cs" />
<Compile Include="Methods\PakReader\ExportObject\USoundWave\USoundWave.cs" />
<Compile Include="Methods\PakReader\Extensions.cs" />
<Compile Include="Methods\PakReader\ExportObject\UScript\UScriptStruct\FByteBulkData.cs" />
<Compile Include="Methods\PakReader\ExportObject\UScript\UScriptStruct\FByteBulkDataHeader.cs" />
<Compile Include="Methods\PakReader\ExportObject\UScript\UScriptStruct\FNameEntrySerialized.cs" />
<Compile Include="Methods\PakReader\ExportObject\UScript\UScriptStruct\FObjectImport.cs" />
<Compile Include="Methods\PakReader\ExportObject\UScript\UScriptStruct\FStripDataFlags.cs" />
<Compile Include="Methods\PakReader\ExportObject\FontFace\FontFace.cs" />
<Compile Include="Methods\PakReader\ImageExporter.cs" />
<Compile Include="Methods\PakReader\LocReader.cs" />
<Compile Include="Methods\PakReader\MeshExporter.cs" />
@ -244,7 +308,27 @@
<Compile Include="Methods\PakReader\PakIndex.cs" />
<Compile Include="Methods\PakReader\PakReader.cs" />
<Compile Include="Methods\PakReader\SigReader.cs" />
<Compile Include="Methods\PakReader\ExportObject\UScript\UScriptStruct\FTexturePlatformData\FTexture2DMipMap.cs" />
<Compile Include="Methods\PakReader\ExportObject\UScript\UScriptStruct\FTexturePlatformData\FTexturePlatformData.cs" />
<Compile Include="Methods\PakReader\ExportObject\Texture2D\Texture2D.cs" />
<Compile Include="Methods\PakReader\ExportObject\UCurveTable\ECurveTableMode.cs" />
<Compile Include="Methods\PakReader\ExportObject\UCurveTable\UCurveTable.cs" />
<Compile Include="Methods\PakReader\ExportObject\UDataTable\UDataTable.cs" />
<Compile Include="Methods\PakReader\UDicReader.cs" />
<Compile Include="Methods\PakReader\ExportObject\UScript\UScriptStruct\FBoxSphereBounds.cs" />
<Compile Include="Methods\PakReader\ExportObject\UScript\UScriptStruct\FReferenceSkeleton\FMeshBoneInfo.cs" />
<Compile Include="Methods\PakReader\ExportObject\UScript\UScriptStruct\FSkeletalMaterial\FMeshUVChannelInfo.cs" />
<Compile Include="Methods\PakReader\ExportObject\UScript\UScriptStruct\FReferenceSkeleton\FReferenceSkeleton.cs" />
<Compile Include="Methods\PakReader\ExportObject\UScript\UScriptStruct\FSkeletalMaterial\FSkeletalMaterial.cs" />
<Compile Include="Methods\PakReader\ExportObject\UScript\UScriptStruct\FStaticLODModel\FSkelMeshSection\FApexClothPhysToRenderVertData.cs" />
<Compile Include="Methods\PakReader\ExportObject\UScript\UScriptStruct\FStaticLODModel\FSkelMeshSection\FClothingSectionData.cs" />
<Compile Include="Methods\PakReader\ExportObject\UScript\UScriptStruct\FStaticLODModel\FSkelMeshSection\FDuplicatedVerticesBuffer\FDuplicatedVerticesBuffer.cs" />
<Compile Include="Methods\PakReader\ExportObject\UScript\UScriptStruct\FStaticLODModel\FSkelMeshSection\FDuplicatedVerticesBuffer\FIndexLengthPair.cs" />
<Compile Include="Methods\PakReader\ExportObject\UScript\UScriptStruct\FStaticLODModel\FSkelMeshSection\FSkelMeshSection.cs" />
<Compile Include="Methods\PakReader\ExportObject\UScript\UScriptStruct\FStaticLODModel\FVector4.cs" />
<Compile Include="Methods\PakReader\ExportObject\UScript\UScriptStruct\FStaticLODModel\FStaticLODModel.cs" />
<Compile Include="Methods\PakReader\ExportObject\UScript\UScriptStruct\FReferenceSkeleton\FTransform.cs" />
<Compile Include="Methods\PakReader\ExportObject\USkeletalMesh\USkeletalMesh.cs" />
<Compile Include="Methods\PAKs\BackupPAKs.cs" />
<Compile Include="Methods\PAKs\PAKsLoader.cs" />
<Compile Include="Methods\PAKs\RegisterFromPath.cs" />

View File

@ -43,7 +43,7 @@
<MenuItem x:Name="MI_BackupPAKs" Header="Backup PAKs" Click="MI_BackupPAKs_Click" IsEnabled="False"/>
<Separator/>
<MenuItem x:Name="MI_DifferenceMode" Header="Difference Mode" IsCheckable="True" Checked="MI_Change_Header" Unchecked="MI_Change_Header"/>
<MenuItem x:Name="MI_UpdateMode" Header="Update Mode (Coming Soon)" IsCheckable="True" Checked="MI_Change_Header" Unchecked="MI_Change_Header" IsEnabled="False"/>
<MenuItem x:Name="MI_UpdateMode" Header="Lazy Mode" IsCheckable="True" Checked="MI_Change_Header" Unchecked="MI_Change_Header" IsEnabled="False"/>
<Separator/>
<MenuItem x:Name="MI_Settings" Header="Settings" InputGestureText="F1" Command="{x:Static commands:FModel_Commands.OpenSettings}">
<MenuItem.Icon>

View File

@ -39,12 +39,12 @@ namespace FModel
AutoUpdater.Start("https://dl.dropbox.com/s/3kv2pukqu6tj1r0/FModel.xml?dl=0");
// Copy user settings from previous application version if necessary
/*if (FProp.Default.FUpdateSettings)
if (FProp.Default.FUpdateSettings)
{
FProp.Default.Upgrade();
FProp.Default.FUpdateSettings = false;
FProp.Default.Save();
}*/
}
await Task.Run(() =>
{

View File

@ -20,7 +20,8 @@
<TextBox x:Name="InputTextBox" Height="19" Margin="41,4,35,0" TextWrapping="NoWrap" VerticalAlignment="Top" Foreground="#FFEFEFEF"/>
<Button x:Name="BrowseInput_Button" Content="..." HorizontalAlignment="Left" Margin="532,4,0,0" VerticalAlignment="Top" Width="20" Click="BrowseInput_Button_Click"/>
<CheckBox x:Name="bDiffFileSize" Content="Diff w/ File Size" HorizontalAlignment="Left" Margin="10,31,0,0" VerticalAlignment="Top"/>
<CheckBox x:Name="checkReloadAES" Content="Reload AES Keys at Launch" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="120,31,0,0" Width="148" IsChecked="True"/>
<CheckBox x:Name="bReloadAES" Content="Reload AES Keys at Launch" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="124,31,0,0" IsChecked="True"/>
<CheckBox x:Name="bOpenSounds" Content="Auto Open Sounds" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="292,31,0,0" IsChecked="True"/>
</Grid>
</GroupBox>
<GroupBox Header="Extraction" HorizontalAlignment="Left" Height="48" Margin="10,85,0,0" VerticalAlignment="Top" Width="574" BorderBrush="#7F748198">

View File

@ -108,7 +108,8 @@ namespace FModel.Forms
InputTextBox.Text = FProp.Default.FPak_Path;
bDiffFileSize.IsChecked = FProp.Default.FDiffFileSize;
OutputTextBox.Text = FProp.Default.FOutput_Path;
checkReloadAES.IsChecked = FProp.Default.ReloadAES;
bReloadAES.IsChecked = FProp.Default.ReloadAES;
bOpenSounds.IsChecked = FProp.Default.FOpenSounds;
ComboBox_Language.SelectedIndex = (int)GetEnumValueFromDescription<LIndexes>(FProp.Default.FLanguage);
ComboBox_Design.SelectedIndex = (int)GetEnumValueFromDescription<RIndexes>(FProp.Default.FRarity_Design);
@ -140,7 +141,8 @@ namespace FModel.Forms
}
FProp.Default.FDiffFileSize = (bool)bDiffFileSize.IsChecked;
FProp.Default.ReloadAES = (bool)checkReloadAES.IsChecked;
FProp.Default.ReloadAES = (bool)bReloadAES.IsChecked;
FProp.Default.FOpenSounds = (bool)bOpenSounds.IsChecked;
if (!string.Equals(FProp.Default.FOutput_Path, OutputTextBox.Text))
{

View File

@ -1,6 +1,11 @@
using FModel.Methods.Utilities;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using PakReader;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;
@ -21,35 +26,7 @@ namespace FModel.Methods.Assets.IconCreator
}
else if (serieToken != null)
{
switch (serieToken.Value<string>())
{
case "MarvelSeries":
DrawBackground(ImagesUtility.ParseColorFromHex("#CB232D"), ImagesUtility.ParseColorFromHex("#7F0E1D"), ImagesUtility.ParseColorFromHex("#FF433D"));
break;
case "CUBESeries":
DrawBackground(ImagesUtility.ParseColorFromHex("#9D006C"), ImagesUtility.ParseColorFromHex("#610064"), ImagesUtility.ParseColorFromHex("#AF1BB9"));
DrawSerieImage("/FortniteGame/Content/Athena/UI/Series/Art/DCU-Series/T-Cube-Background");
break;
case "DCUSeries":
DrawBackground(ImagesUtility.ParseColorFromHex("#2D445D"), ImagesUtility.ParseColorFromHex("#101928"), ImagesUtility.ParseColorFromHex("#3E5E7A"));
DrawSerieImage("/FortniteGame/Content/Athena/UI/Series/Art/DCU-Series/T-BlackMonday-Background");
break;
case "CreatorCollabSeries":
DrawBackground(ImagesUtility.ParseColorFromHex("#158588"), ImagesUtility.ParseColorFromHex("#073A4A"), ImagesUtility.ParseColorFromHex("#3FB3AA"));
DrawSerieImage("/FortniteGame/Content/Athena/UI/Series/Art/DCU-Series/T_Ui_CreatorsCollab_Bg");
break;
case "FrozenSeries":
DrawBackground(ImagesUtility.ParseColorFromHex("#5D9BC9"), ImagesUtility.ParseColorFromHex("#77C2E5"), ImagesUtility.ParseColorFromHex("#0296C9"));
DrawSerieImage("/FortniteGame/Content/Athena/UI/Series/Art/DCU-Series/T_Ui_LavaSeries_Frozen");
break;
case "LavaSeries":
DrawBackground(ImagesUtility.ParseColorFromHex("#5E0536"), ImagesUtility.ParseColorFromHex("#4D065F"), ImagesUtility.ParseColorFromHex("#A61835"));
DrawSerieImage("/FortniteGame/Content/Athena/UI/Series/Art/DCU-Series/T_Ui_LavaSeries_Bg");
break;
default:
DrawNormalRarity(rarityToken);
break;
}
GetSerieAsset(serieToken, rarityToken);
}
else
{
@ -143,6 +120,59 @@ namespace FModel.Methods.Assets.IconCreator
}
}
private static void GetSerieAsset(JToken serieToken, JToken rarityToken)
{
//this will catch the full path if asset exists to be able to grab his PakReader and List<FPakEntry>
string seriesFullPath = AssetEntries.AssetEntriesDict.Where(x => x.Key.ToLowerInvariant().Contains("/" + serieToken.Value<string>().ToLowerInvariant() + ".uasset")).Select(d => d.Key).FirstOrDefault();
if (!string.IsNullOrEmpty(seriesFullPath))
{
string path = seriesFullPath.Substring(0, seriesFullPath.LastIndexOf(".", StringComparison.InvariantCultureIgnoreCase));
PakReader.PakReader reader = AssetsUtility.GetPakReader(path);
if (reader != null)
{
List<FPakEntry> entriesList = AssetsUtility.GetPakEntries(path);
string jsonData = AssetsUtility.GetAssetJsonData(reader, entriesList);
if (AssetsUtility.IsValidJson(jsonData))
{
dynamic AssetData = JsonConvert.DeserializeObject(jsonData);
JToken AssetMainToken = null;
if (jsonData.StartsWith("[") && jsonData.EndsWith("]"))
{
JArray AssetArray = JArray.FromObject(AssetData);
AssetMainToken = AssetArray[0];
}
else if (jsonData.StartsWith("{") && jsonData.EndsWith("}"))
{
AssetMainToken = AssetData;
}
if (AssetMainToken != null)
{
JArray propertiesArray = AssetMainToken["properties"].Value<JArray>();
if (propertiesArray != null)
{
JArray colorsArray = AssetsUtility.GetPropertyTagStruct<JArray>(propertiesArray, "Colors", "properties");
if (colorsArray != null)
{
DrawSerieBackground(colorsArray);
}
JToken backgroundTextureToken = AssetsUtility.GetPropertyTagText<JToken>(propertiesArray, "BackgroundTexture", "asset_path_name");
if (backgroundTextureToken != null)
{
string imagePath = FoldersUtility.FixFortnitePath(backgroundTextureToken.Value<string>());
DrawSerieImage(imagePath);
}
}
}
}
}
else { DrawNormalRarity(rarityToken); }
}
else { DrawNormalRarity(rarityToken); }
}
private static void DrawSerieImage(string AssetPath)
{
using (Stream image = AssetsUtility.GetStreamImageFromPath(AssetPath))
@ -156,10 +186,78 @@ namespace FModel.Methods.Assets.IconCreator
bmp.EndInit();
bmp.Freeze();
IconCreator.ICDrawingContext.DrawImage(ImagesUtility.CreateTransparency(bmp, 100), new Rect(3, 3, 509, 509));
IconCreator.ICDrawingContext.DrawImage(bmp, new Rect(3, 3, 509, 509));
}
}
}
private static void DrawSerieBackground(JArray colorsArray)
{
Color background = new Color();
Color backgroundupdown = new Color();
Color border = new Color();
JToken backgroundRed = AssetsUtility.GetPropertyTagStruct<JToken>(colorsArray, "Color3", "r");
JToken backgroundGreen = AssetsUtility.GetPropertyTagStruct<JToken>(colorsArray, "Color3", "g");
JToken backgroundBlue = AssetsUtility.GetPropertyTagStruct<JToken>(colorsArray, "Color3", "b");
if (backgroundRed != null && backgroundGreen != null && backgroundBlue != null)
{
int r = (int)(backgroundRed.Value<double>() * 255);
int g = (int)(backgroundGreen.Value<double>() * 255);
int b = (int)(backgroundBlue.Value<double>() * 255);
background = Color.FromRgb((byte)r, (byte)g, (byte)b);
}
JToken backgroundupdownRed = AssetsUtility.GetPropertyTagStruct<JToken>(colorsArray, "Color1", "r");
JToken backgroundupdownGreen = AssetsUtility.GetPropertyTagStruct<JToken>(colorsArray, "Color1", "g");
JToken backgroundupdownBlue = AssetsUtility.GetPropertyTagStruct<JToken>(colorsArray, "Color1", "b");
if (backgroundupdownRed != null && backgroundupdownGreen != null && backgroundupdownBlue != null)
{
int r = (int)(backgroundupdownRed.Value<double>() * 255);
int g = (int)(backgroundupdownGreen.Value<double>() * 255);
int b = (int)(backgroundupdownBlue.Value<double>() * 255);
backgroundupdown = Color.FromRgb((byte)r, (byte)g, (byte)b);
}
JToken borderRed = AssetsUtility.GetPropertyTagStruct<JToken>(colorsArray, "Color2", "r");
JToken borderGreen = AssetsUtility.GetPropertyTagStruct<JToken>(colorsArray, "Color2", "g");
JToken borderBlue = AssetsUtility.GetPropertyTagStruct<JToken>(colorsArray, "Color2", "b");
if (borderRed != null && borderGreen != null && borderBlue != null)
{
int r = (int)(borderRed.Value<double>() * 255);
int g = (int)(borderGreen.Value<double>() * 255);
int b = (int)(borderBlue.Value<double>() * 255);
border = Color.FromRgb((byte)r, (byte)g, (byte)b);
}
DrawBackground(backgroundupdown, background, ChangeColorBrightness(border, 0.25f));
}
public static Color ChangeColorBrightness(Color color, float correctionFactor)
{
float red = color.R;
float green = color.G;
float blue = color.B;
if (correctionFactor < 0)
{
correctionFactor = 1 + correctionFactor;
red *= correctionFactor;
green *= correctionFactor;
blue *= correctionFactor;
}
else
{
red = (255 - red) * correctionFactor + red;
green = (255 - green) * correctionFactor + green;
blue = (255 - blue) * correctionFactor + blue;
}
return Color.FromRgb((byte)red, (byte)green, (byte)blue);
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,735 @@
using System;
using System.IO;
using System.Linq;
using System.Text;
namespace PakReader
{
public class AssetReader
{
public readonly ExportObject[] Exports;
public AssetReader(string path, bool ubulk = false, bool ignoreErrors = true) : this(path + ".uasset", path + ".uexp", ubulk ? path + ".ubulk" : null, ignoreErrors) { }
public AssetReader(string assetPath, string expPath, string bulkPath, bool ignoreErrors = true) : this(File.OpenRead(assetPath), File.OpenRead(expPath), bulkPath == null ? null : File.OpenRead(bulkPath), ignoreErrors) { }
public AssetReader(Stream asset, Stream exp, Stream bulk = null, bool ignoreErrors = true)
{
BinaryReader reader = new BinaryReader(asset);
var summary = new AssetSummary(reader);
reader.BaseStream.Seek(summary.name_offset, SeekOrigin.Begin);
FNameEntrySerialized[] name_map = new FNameEntrySerialized[summary.name_count];
for (int i = 0; i < summary.name_count; i++)
{
name_map[i] = new FNameEntrySerialized(reader);
}
reader.BaseStream.Seek(summary.import_offset, SeekOrigin.Begin);
FObjectImport[] import_map = new FObjectImport[summary.import_count];
for (int i = 0; i < summary.import_count; i++)
{
import_map[i] = new FObjectImport(reader, name_map, import_map);
}
reader.BaseStream.Seek(summary.export_offset, SeekOrigin.Begin);
FObjectExport[] export_map = new FObjectExport[summary.export_count];
for (int i = 0; i < summary.export_count; i++)
{
export_map[i] = new FObjectExport(reader, name_map, import_map);
}
long export_size = export_map.Sum(v => v.serial_size);
reader = new BinaryReader(exp);
var bulkReader = bulk == null ? null : new BinaryReader(bulk);
int asset_length = summary.total_header_size;
Exports = new ExportObject[summary.export_count];
int ind = 0;
foreach (FObjectExport v in export_map)
{
string export_type = v.class_index.import;
long position = v.serial_offset - asset.Length;
reader.BaseStream.Seek(position, SeekOrigin.Begin);
try
{
switch (export_type)
{
case "Texture2D":
Exports[ind] = new Texture2D(reader, name_map, import_map, asset_length, export_size, bulkReader);
break;
case "FontFace":
Exports[ind] = new FontFace(reader, name_map, import_map);
break;
case "DataTable":
Exports[ind] = new UDataTable(reader, name_map, import_map);
break;
case "CurveTable":
Exports[ind] = new UCurveTable(reader, name_map, import_map);
break;
case "SkeletalMesh":
Exports[ind] = new USkeletalMesh(reader, name_map, import_map);
break;
case "AnimSequence":
Exports[ind] = new UAnimSequence(reader, name_map, import_map);
break;
case "Skeleton":
Exports[ind] = new USkeleton(reader, name_map, import_map);
break;
case "SoundWave":
Exports[ind] = new USoundWave(reader, name_map, import_map, asset_length, export_size, bulkReader);
break;
default:
Exports[ind] = new UObject(reader, name_map, import_map, export_type, true);
break;
}
}
catch (Exception e)
{
if (!ignoreErrors)
throw e;
}
long valid_pos = position + v.serial_size;
if (reader.BaseStream.Position != valid_pos)
{
Console.WriteLine($"Did not read {export_type} correctly. Current Position: {reader.BaseStream.Position}, Bytes Remaining: {valid_pos - reader.BaseStream.Position}");
reader.BaseStream.Seek(valid_pos, SeekOrigin.Begin);
}
ind++;
}
//Exports[Exports.Length - 1] = new AssetInfo(name_map, import_map, export_map);
}
/*public class AssetInfo : ExportObject
{
[JsonProperty]
FNameEntrySerialized[] name_map;
[JsonProperty]
FObjectImport[] import_map;
[JsonProperty]
FObjectExport[] export_map;
internal AssetInfo(FNameEntrySerialized[] name_map, FObjectImport[] import_map, FObjectExport[] export_map)
{
this.name_map = name_map;
this.import_map = import_map;
this.export_map = export_map;
}
}*/
static readonly uint[] _Lookup32 = Enumerable.Range(0, 256).Select(i => {
string s = i.ToString("X2");
return s[0] + ((uint)s[1] << 16);
}).ToArray();
internal static string ToHex(params byte[] bytes)
{
var result = new char[bytes.Length * 2];
for (int i = 0; i < bytes.Length; i++)
{
var val = _Lookup32[bytes[i]];
result[2 * i] = (char)val;
result[2 * i + 1] = (char)(val >> 16);
}
return new string(result);
}
internal static string read_string(BinaryReader reader)
{
int length = reader.ReadInt32();
if (length > 65536 || length < -65536)
{
throw new IOException($"String length too large ({length}), likely a read error.");
}
if (length == 0)
{
return "";
}
if (length < 0)
{
length *= -1;
ushort[] data = new ushort[length];
for (int i = 0; i < length; i++)
{
data[i] = reader.ReadUInt16();
}
unsafe
{
fixed (ushort* dataPtr = &data[0])
return new string((char*)dataPtr, 0, data.Length).TrimEnd('\0');
}
}
else
{
byte[] bytes = reader.ReadBytes(length);
if (bytes.Length == 0) return string.Empty;
var ret = Encoding.UTF8.GetString(bytes).TrimEnd('\0');
if (ret.Length != length)
{
return ret;
}
else
{
return ret.Substring(0, length - 1);
}
}
}
public static T[] read_tarray<T>(BinaryReader reader, Func<BinaryReader, T> getter)
{
uint length = reader.ReadUInt32();
T[] container = new T[length];
for (int i = 0; i < length; i++)
{
container[i] = getter(reader);
}
return container;
}
internal static string read_fname(BinaryReader reader, FNameEntrySerialized[] name_map)
{
long index_pos = reader.BaseStream.Position;
int name_index = reader.ReadInt32();
reader.ReadInt32(); //name number ?
if (name_index >= 0 && name_index < name_map.Length)
{
return name_map[name_index].data;
}
else
{
throw new IOException(string.Format("FName could not be read at offset {0} Requested Index: {1}, Name Map Size: {2}", index_pos, name_index, name_map.Length));
}
}
static object tag_data_overrides(string name)
{
switch (name)
{
case "BindingIdToReferences":
return ("Guid", "LevelSequenceBindingReferenceArray");
case "Tracks":
return ("MovieSceneTrackIdentifier", "MovieSceneEvaluationTrack");
case "SubTemplateSerialNumbers":
return ("MovieSceneSequenceID", "UInt32Property");
case "SubSequences":
return ("MovieSceneSequenceID", "MovieSceneSubSequenceData");
case "Hierarchy":
return ("MovieSceneSequenceID", "MovieSceneSequenceHierarchyNode");
case "TrackSignatureToTrackIdentifier":
return ("Guid", "MovieSceneTrackIdentifier");
case "SubSectionRanges":
return ("Guid", "MovieSceneFrameRange");
default:
return default;
}
}
internal static FPropertyTag read_property_tag(BinaryReader reader, FNameEntrySerialized[] name_map, FObjectImport[] import_map, bool read_data)
{
string name = read_fname(reader, name_map);
if (name == "None")
{
return default;
}
string property_type = read_fname(reader, name_map).Trim();
int size = reader.ReadInt32();
int array_index = reader.ReadInt32();
object tag_data;
switch (property_type)
{
case "StructProperty":
tag_data = (read_fname(reader, name_map), new FGuid(reader));
break;
case "BoolProperty":
tag_data = reader.ReadByte() != 0;
break;
case "EnumProperty":
tag_data = read_fname(reader, name_map);
break;
case "ByteProperty":
tag_data = read_fname(reader, name_map);
break;
case "ArrayProperty":
tag_data = read_fname(reader, name_map);
break;
case "MapProperty":
tag_data = (read_fname(reader, name_map), read_fname(reader, name_map));
break;
case "SetProperty":
tag_data = read_fname(reader, name_map);
break;
default:
tag_data = null;
break;
}
if (property_type == "MapProperty")
{
tag_data = tag_data_overrides(name) ?? tag_data;
}
bool has_property_guid = reader.ReadByte() != 0;
FGuid property_guid = has_property_guid ? new FGuid(reader) : default;
long pos = reader.BaseStream.Position;
var (type, data) = read_data ? new_property_tag_type(reader, name_map, import_map, property_type, tag_data) : default;
if ((int)type == 100)
{
return default;
}
if (read_data)
{
reader.BaseStream.Seek(pos + size, SeekOrigin.Begin);
}
if (read_data && pos + size != reader.BaseStream.Position)
{
throw new IOException($"Could not read entire property: {name} ({property_type})");
}
return new FPropertyTag
{
array_index = array_index,
name = name,
position = pos,
property_guid = property_guid,
property_type = property_type,
size = size,
tag = type,
tag_data = read_data ? data : tag_data
};
}
internal static (FPropertyTagType type, object data) new_property_tag_type(BinaryReader reader, FNameEntrySerialized[] name_map, FObjectImport[] import_map, string property_type, object tag_data)
{
switch (property_type)
{
case "BoolProperty":
return (FPropertyTagType.BoolProperty, (bool)tag_data);
case "StructProperty":
if (tag_data is UScriptStruct)
{
return (FPropertyTagType.StructProperty, tag_data);
}
return (FPropertyTagType.StructProperty, new UScriptStruct(reader, name_map, import_map, ((ValueTuple<string, FGuid>)tag_data).Item1));
case "ObjectProperty":
return (FPropertyTagType.ObjectProperty, new FPackageIndex(reader, import_map));
case "InterfaceProperty":
return (FPropertyTagType.InterfaceProperty, new UInterfaceProperty(reader));
case "FloatProperty":
return (FPropertyTagType.FloatProperty, reader.ReadSingle());
case "TextProperty":
return (FPropertyTagType.TextProperty, new FText(reader));
case "StrProperty":
return (FPropertyTagType.StrProperty, read_string(reader));
case "NameProperty":
return (FPropertyTagType.NameProperty, read_fname(reader, name_map));
case "IntProperty":
return (FPropertyTagType.IntProperty, reader.ReadInt32());
case "UInt16Property":
return (FPropertyTagType.UInt16Property, reader.ReadUInt16());
case "UInt32Property":
return (FPropertyTagType.UInt32Property, reader.ReadUInt32());
case "UInt64Property":
return (FPropertyTagType.UInt64Property, reader.ReadUInt64());
case "ArrayProperty":
return (FPropertyTagType.ArrayProperty, new UScriptArray(reader, (string)tag_data, name_map, import_map));
case "MapProperty":
(string key_type, string value_type) = (ValueTuple<string, string>)tag_data;
return (FPropertyTagType.MapProperty, new UScriptMap(reader, name_map, import_map, key_type, value_type));
case "ByteProperty":
return (FPropertyTagType.ByteProperty, (string)tag_data == "None" ? (object)reader.ReadByte() : read_fname(reader, name_map));
case "EnumProperty":
return (FPropertyTagType.EnumProperty, (string)tag_data == "None" ? null : read_fname(reader, name_map));
case "DelegateProperty":
return (FPropertyTagType.DelegateProperty, new FScriptDelegate(reader, name_map));
case "SoftObjectProperty":
return (FPropertyTagType.SoftObjectProperty, new FSoftObjectPath(reader, name_map));
default:
return ((FPropertyTagType)100, null);
//throw new NotImplementedException($"Could not read property type: {property_type} at pos {reader.BaseStream.Position}");
}
}
public struct AssetSummary
{
internal AssetSummary(BinaryReader reader)
{
tag = reader.ReadInt32();
legacy_file_version = reader.ReadInt32();
legacy_ue3_version = reader.ReadInt32();
file_version_u34 = reader.ReadInt32();
file_version_licensee_ue4 = reader.ReadInt32();
custom_version_container = reader.ReadTArray(() => new FCustomVersion(reader));
total_header_size = reader.ReadInt32();
folder_name = read_string(reader);
package_flags = reader.ReadUInt32();
name_count = reader.ReadInt32();
name_offset = reader.ReadInt32();
gatherable_text_data_count = reader.ReadInt32();
gatherable_text_data_offset = reader.ReadInt32();
export_count = reader.ReadInt32();
export_offset = reader.ReadInt32();
import_count = reader.ReadInt32();
import_offset = reader.ReadInt32();
depends_offset = reader.ReadInt32();
string_asset_references_count = reader.ReadInt32();
string_asset_references_offset = reader.ReadInt32();
searchable_names_offset = reader.ReadInt32();
thumbnail_table_offset = reader.ReadInt32();
guid = new FGuid(reader);
generations = reader.ReadTArray(() => new FGenerationInfo(reader));
saved_by_engine_version = new FEngineVersion(reader);
compatible_with_engine_version = new FEngineVersion(reader);
compression_flags = reader.ReadUInt32();
compressed_chunks = reader.ReadTArray(() => new FCompressedChunk(reader));
package_source = reader.ReadUInt32();
additional_packages_to_cook = reader.ReadTArray(() => read_string(reader));
asset_registry_data_offset = reader.ReadInt32();
buld_data_start_offset = reader.ReadInt32();
world_tile_info_data_offset = reader.ReadInt32();
chunk_ids = reader.ReadTArray(() => reader.ReadInt32());
preload_dependency_count = reader.ReadInt32();
preload_dependency_offset = reader.ReadInt32();
var pos = reader.BaseStream.Position;
reader.BaseStream.Seek(0, SeekOrigin.Begin);
}
public int tag;
public int legacy_file_version;
public int legacy_ue3_version;
public int file_version_u34;
public int file_version_licensee_ue4;
public FCustomVersion[] custom_version_container;
public int total_header_size;
public string folder_name;
public uint package_flags;
public int name_count;
public int name_offset;
public int gatherable_text_data_count;
public int gatherable_text_data_offset;
public int export_count;
public int export_offset;
public int import_count;
public int import_offset;
public int depends_offset;
public int string_asset_references_count;
public int string_asset_references_offset;
public int searchable_names_offset;
public int thumbnail_table_offset;
public FGuid guid;
public FGenerationInfo[] generations;
public FEngineVersion saved_by_engine_version;
public FEngineVersion compatible_with_engine_version;
public uint compression_flags;
public FCompressedChunk[] compressed_chunks;
public uint package_source;
public string[] additional_packages_to_cook;
public int asset_registry_data_offset;
public int buld_data_start_offset;
public int world_tile_info_data_offset;
public int[] chunk_ids;
public int preload_dependency_count;
public int preload_dependency_offset;
}
public struct FCustomVersion
{
public FGuid key;
public int version;
internal FCustomVersion(BinaryReader reader)
{
key = new FGuid(reader);
version = reader.ReadInt32();
}
}
public struct FGenerationInfo
{
public int export_count;
public int name_count;
internal FGenerationInfo(BinaryReader reader)
{
export_count = reader.ReadInt32();
name_count = reader.ReadInt32();
}
}
public struct FEngineVersion
{
public ushort major;
public ushort minor;
public ushort patch;
public uint changelist;
public string branch;
internal FEngineVersion(BinaryReader reader)
{
major = reader.ReadUInt16();
minor = reader.ReadUInt16();
patch = reader.ReadUInt16();
changelist = reader.ReadUInt32();
branch = read_string(reader);
}
}
public struct FCompressedChunk
{
public int uncompressed_offset;
public int uncompressed_size;
public int compressed_offset;
public int compressed_size;
internal FCompressedChunk(BinaryReader reader)
{
uncompressed_offset = reader.ReadInt32();
uncompressed_size = reader.ReadInt32();
compressed_offset = reader.ReadInt32();
compressed_size = reader.ReadInt32();
}
}
public struct FSkelMeshChunk
{
public int BaseVertexIndex;
public FVertex[] RigidVerticies;
public FVertex[] SoftVertices;
public ushort[] BoneMap;
public int NumRigidVertices;
public int NumSoftVertices;
public int MaxBoneInfluences;
public bool HasClothData;
}
public struct FVertex
{
public FVector Pos;
public FPackedNormal[] Normal; // 3 length
public FSkinWeightInfo Infs;
public FMeshUVFloat[] UV; // 4 length
public FColor Color;
public static FVertex Soft(BinaryReader reader) => new FVertex
{
Pos = new FVector(reader),
Normal = new FPackedNormal[]
{
new FVector(reader),
new FVector(reader),
new FVector4(reader)
},
UV = new FMeshUVFloat[]
{
new FMeshUVFloat(reader),
new FMeshUVFloat(reader),
new FMeshUVFloat(reader),
new FMeshUVFloat(reader)
},
Color = new FColor(reader),
Infs = new FSkinWeightInfo(reader)
};
public static FVertex Rigid(BinaryReader reader) => new FVertex
{
Pos = new FVector(reader),
Normal = new FPackedNormal[]
{
new FVector(reader),
new FVector(reader),
new FVector4(reader)
},
UV = new FMeshUVFloat[]
{
new FMeshUVFloat(reader),
new FMeshUVFloat(reader),
new FMeshUVFloat(reader),
new FMeshUVFloat(reader)
},
Color = new FColor(reader),
Infs = new FSkinWeightInfo()
{
bone_index = new byte[] { reader.ReadByte(), 0, 0, 0 },
bone_weight = new byte[] { 255, 0, 0, 0 }
}
};
}
public struct FMeshToMeshVertData
{
public FQuat position_bary_coords;
public FQuat normal_bary_coords;
public FQuat tangent_bary_coords;
public ushort[] source_mesh_vert_indices;
public uint[] padding;
public FMeshToMeshVertData(BinaryReader reader)
{
position_bary_coords = new FQuat(reader);
normal_bary_coords = new FQuat(reader);
tangent_bary_coords = new FQuat(reader);
source_mesh_vert_indices = new ushort[4];
for (int i = 0; i < 4; i++)
{
source_mesh_vert_indices[i] = reader.ReadUInt16();
}
padding = new uint[2];
for (int i = 0; i < 4; i++)
{
padding[i] = reader.ReadUInt32();
}
}
}
internal struct FLevelSequenceObjectReferenceMap
{
public FLevelSequenceLegacyObjectReference[] map_data;
internal FLevelSequenceObjectReferenceMap(BinaryReader reader)
{
int element_count = reader.ReadInt32();
map_data = new FLevelSequenceLegacyObjectReference[element_count];
for (int i = 0; i < element_count; i++)
{
map_data[i] = new FLevelSequenceLegacyObjectReference(reader);
}
}
}
internal struct FLevelSequenceLegacyObjectReference
{
public FGuid key_guid;
public FGuid object_id;
public string object_path;
internal FLevelSequenceLegacyObjectReference(BinaryReader reader)
{
key_guid = new FGuid(reader);
object_id = new FGuid(reader);
object_path = read_string(reader);
}
}
internal struct FSectionEvaluationDataTree
{
public TMovieSceneEvaluationTree<FStructFallback> tree;
internal FSectionEvaluationDataTree(BinaryReader reader, FNameEntrySerialized[] name_map, FObjectImport[] import_map)
{
tree = new TMovieSceneEvaluationTree<FStructFallback>(reader, name_map, import_map);
}
}
internal struct TMovieSceneEvaluationTree<T>
{
public FMovieSceneEvaluationTree base_tree;
public TEvaluationTreeEntryContainer<T> data;
internal TMovieSceneEvaluationTree(BinaryReader reader, FNameEntrySerialized[] name_map, FObjectImport[] import_map)
{
base_tree = new FMovieSceneEvaluationTree(reader);
data = new TEvaluationTreeEntryContainer<T>(reader);
}
}
internal struct FMovieSceneEvaluationTree
{
public FMovieSceneEvaluationTreeNode root_node;
public TEvaluationTreeEntryContainer<FMovieSceneEvaluationTreeNode> child_nodes;
internal FMovieSceneEvaluationTree(BinaryReader reader)
{
root_node = new FMovieSceneEvaluationTreeNode(reader);
child_nodes = new TEvaluationTreeEntryContainer<FMovieSceneEvaluationTreeNode>(reader);
}
}
internal struct FMovieSceneEvaluationTreeNode
{
internal FMovieSceneEvaluationTreeNode(BinaryReader reader)
{
// holy shit this goes on forever
throw new NotImplementedException("Not implemented yet.");
}
}
internal struct TEvaluationTreeEntryContainer<T>
{
public FEntry[] entries;
public T[] items;
internal TEvaluationTreeEntryContainer(BinaryReader reader)
{
entries = reader.ReadTArray(() => new FEntry(reader));
items = null;
throw new NotImplementedException("Not implemented yet.");
}
}
internal struct FEntry
{
public int start_index;
public int size;
public int capacity;
internal FEntry(BinaryReader reader)
{
start_index = reader.ReadInt32();
size = reader.ReadInt32();
capacity = reader.ReadInt32();
}
}
internal struct UInterfaceProperty
{
public uint interface_number;
internal UInterfaceProperty(BinaryReader reader)
{
interface_number = reader.ReadUInt32();
}
}
internal static object read_map_value(BinaryReader reader, string inner_type, string struct_type, FNameEntrySerialized[] name_map, FObjectImport[] import_map)
{
switch (inner_type)
{
case "BoolProperty":
return reader.ReadByte() != 1;
case "ByteProperty":
return reader.ReadByte();
case "EnumProperty":
return read_fname(reader, name_map);
case "IntProperty":
return reader.ReadInt32();
case "UInt32Property":
return reader.ReadUInt32();
case "StructProperty":
return new UScriptStruct(reader, name_map, import_map, struct_type);
case "NameProperty":
return read_fname(reader, name_map);
case "ObjectProperty":
return new FPackageIndex(reader, import_map);
case "SoftObjectProperty":
return (FPropertyTagType.SoftObjectPropertyMap, new FGuid(reader));
case "StrProperty":
return read_string(reader);
case "TextProperty":
return new FText(reader);
default:
return (FPropertyTagType.StructProperty, new UScriptStruct(reader, name_map, import_map, inner_type));
}
}
}
}

View File

@ -0,0 +1,4 @@
namespace PakReader
{
public abstract class ExportObject { }
}

View File

@ -0,0 +1,22 @@
using Newtonsoft.Json;
using System.IO;
namespace PakReader
{
public sealed class FontFace : ExportObject
{
public UObject base_object;
[JsonIgnore]
public uint data;
internal FontFace(BinaryReader reader, FNameEntrySerialized[] name_map, FObjectImport[] import_map)
{
base_object = new UObject(reader, name_map, import_map, "FontFace", true);
new FStripDataFlags(reader); // no idea
new FStripDataFlags(reader); // why are there two
data = reader.ReadUInt32();
}
}
}

View File

@ -0,0 +1,50 @@
using SkiaSharp;
using System;
using System.Collections.Generic;
using System.IO;
using static PakReader.AssetReader;
namespace PakReader
{
public sealed class Texture2D : ExportObject, IDisposable
{
public UObject base_object;
public bool cooked;
internal FTexturePlatformData[] textures;
internal Texture2D(BinaryReader reader, FNameEntrySerialized[] name_map, FObjectImport[] import_map, int asset_file_size, long export_size, BinaryReader ubulk)
{
var uobj = new UObject(reader, name_map, import_map, "Texture2D", true);
new FStripDataFlags(reader); // no idea
new FStripDataFlags(reader); // why are there two
List<FTexturePlatformData> texs = new List<FTexturePlatformData>();
cooked = reader.ReadUInt32() == 1;
if (cooked)
{
string pixel_format = read_fname(reader, name_map);
while (pixel_format != "None")
{
long skipOffset = reader.ReadInt64();
var texture = new FTexturePlatformData(reader, ubulk, export_size + asset_file_size);
if (reader.BaseStream.Position + asset_file_size != skipOffset)
{
throw new IOException("Texture read incorrectly");
}
texs.Add(texture);
pixel_format = read_fname(reader, name_map);
}
}
textures = texs.ToArray();
}
public SKImage GetImage() => ImageExporter.GetImage(textures[0].mips[0], textures[0].pixel_format);
public void Dispose()
{
textures = null;
}
}
}

View File

@ -0,0 +1,350 @@
using System;
using System.IO;
namespace PakReader
{
public sealed class UAnimSequence : ExportObject
{
public UObject super_object;
public FGuid skeleton_guid;
public byte key_encoding_format;
public byte translation_compression_format;
public byte rotation_compression_format;
public byte scale_compression_format;
public int[] compressed_track_offsets;
public FCompressedOffsetData compressed_scale_offsets;
public FCompressedSegment[] compressed_segments;
public int[] compressed_track_to_skeleton_table;
public FSmartName[] compressed_curve_names;
public int compressed_raw_data_size;
public int compressed_num_frames;
public FTrack[] tracks;
internal UAnimSequence(BinaryReader reader, FNameEntrySerialized[] name_map, FObjectImport[] import_map)
{
super_object = new UObject(reader, name_map, import_map, "AnimSequence", true);
skeleton_guid = new FGuid(reader);
new FStripDataFlags(reader);
if (reader.ReadUInt32() == 0)
{
throw new FileLoadException("Could not decode AnimSequence (must be compressed)");
}
key_encoding_format = reader.ReadByte();
translation_compression_format = reader.ReadByte();
rotation_compression_format = reader.ReadByte();
scale_compression_format = reader.ReadByte();
compressed_track_offsets = reader.ReadTArray(() => reader.ReadInt32());
compressed_scale_offsets = new FCompressedOffsetData
{
offset_data = reader.ReadTArray(() => reader.ReadInt32()),
strip_size = reader.ReadInt32()
};
compressed_segments = reader.ReadTArray(() => new FCompressedSegment(reader));
compressed_track_to_skeleton_table = reader.ReadTArray(() => reader.ReadInt32());
compressed_curve_names = reader.ReadTArray(() => new FSmartName(reader, name_map));
compressed_raw_data_size = reader.ReadInt32();
compressed_num_frames = reader.ReadInt32();
int num_bytes = reader.ReadInt32();
if (reader.ReadUInt32() != 0)
{
throw new NotImplementedException("Bulk data for animations not supported yet");
}
tracks = read_tracks(new MemoryStream(reader.ReadBytes(num_bytes)));
}
static float read_fixed48(ushort val) => val - 255f;
static float read_fixed48_q(ushort val) => (val / 32767f) - 1;
const uint X_MASK = 0x000003ff;
const uint Y_MASK = 0x001ffc00;
static FVector read_fixed32_vec(uint val, FVector min, FVector max)
{
return new FVector
{
X = ((val & X_MASK) - 511) / 511f * max.X + min.X,
Y = (((val & Y_MASK) >> 10) - 1023) / 1023f * max.Y + min.Y,
Z = ((val >> 21) - 1023) / 1023f * max.Z + min.Z
};
}
static FQuat read_fixed32_quat(uint val, FVector min, FVector max)
{
var q = new FQuat
{
X = ((val >> 21) - 1023) / 1023f * max.X + min.X,
Y = (((val & Y_MASK) >> 10) - 1023) / 1023f * max.Y + min.Y,
Z = ((val & X_MASK) - 511) / 511f * max.Z + min.Z,
W = 1
};
q.rebuild_w();
return q;
}
static void align_reader(BinaryReader reader)
{
var pos = reader.BaseStream.Position % 4;
if (pos != 0) reader.BaseStream.Seek(4 - pos, SeekOrigin.Current);
}
static float[] read_times(BinaryReader reader, uint num_keys, uint num_frames)
{
if (num_keys <= 1) return new float[0];
align_reader(reader);
var ret = new float[num_keys];
if (num_frames < 256)
{
for (int i = 0; i < num_keys; i++)
{
ret[i] = reader.ReadByte();
}
}
else
{
for (int i = 0; i < num_keys; i++)
{
ret[i] = reader.ReadUInt16();
}
}
return ret;
}
private FTrack[] read_tracks(MemoryStream stream)
{
if (key_encoding_format != 2)
{
throw new NotImplementedException("Can only parse PerTrackCompression");
}
using (stream)
using (var reader = new BinaryReader(stream))
{
var num_tracks = compressed_track_offsets.Length / 2;
var num_frames = compressed_num_frames;
FTrack[] ret = new FTrack[num_tracks];
for (int i = 0; i < ret.Length; i++)
{
FTrack track = new FTrack();
// translation
var offset = compressed_track_offsets[i * 2];
if (offset != -1)
{
var header = new FAnimKeyHeader(reader);
var min = new FVector();
var max = new FVector();
if (header.key_format == AnimationCompressionFormat.IntervalFixed32NoW)
{
if ((header.component_mask & 1) != 0)
{
min.X = reader.ReadSingle();
max.X = reader.ReadSingle();
}
if ((header.component_mask & 2) != 0)
{
min.Y = reader.ReadSingle();
max.Y = reader.ReadSingle();
}
if ((header.component_mask & 4) != 0)
{
min.Z = reader.ReadSingle();
max.Z = reader.ReadSingle();
}
}
track.translation = new FVector[header.num_keys];
for (int j = 0; j < track.translation.Length; j++)
{
switch (header.key_format)
{
case AnimationCompressionFormat.None:
case AnimationCompressionFormat.Float96NoW:
var fvec = new FVector();
if ((header.component_mask & 7) != 0)
{
if ((header.component_mask & 1) != 0) fvec.X = reader.ReadSingle();
if ((header.component_mask & 2) != 0) fvec.Y = reader.ReadSingle();
if ((header.component_mask & 4) != 0) fvec.Z = reader.ReadSingle();
}
else
{
fvec = new FVector(reader);
}
track.translation[j] = fvec;
break;
case AnimationCompressionFormat.Fixed48NoW:
fvec = new FVector();
if ((header.component_mask & 1) != 0) fvec.X = read_fixed48(reader.ReadUInt16());
if ((header.component_mask & 2) != 0) fvec.Y = read_fixed48(reader.ReadUInt16());
if ((header.component_mask & 4) != 0) fvec.Z = read_fixed48(reader.ReadUInt16());
track.translation[j] = fvec;
break;
case AnimationCompressionFormat.IntervalFixed32NoW:
track.translation[j] = read_fixed32_vec(reader.ReadUInt32(), min, max);
break;
}
}
if (header.has_time_tracks)
{
track.translation_times = read_times(reader, header.num_keys, (uint)num_frames);
}
align_reader(reader);
}
// rotation
offset = compressed_track_offsets[(i * 2) + 1];
if (offset != -1)
{
var header = new FAnimKeyHeader(reader);
var min = new FVector();
var max = new FVector();
if (header.key_format == AnimationCompressionFormat.IntervalFixed32NoW)
{
if ((header.component_mask & 1) != 0)
{
min.X = reader.ReadSingle();
max.X = reader.ReadSingle();
}
if ((header.component_mask & 2) != 0)
{
min.Y = reader.ReadSingle();
max.Y = reader.ReadSingle();
}
if ((header.component_mask & 4) != 0)
{
min.Z = reader.ReadSingle();
max.Z = reader.ReadSingle();
}
}
track.rotation = new FQuat[header.num_keys];
for (int j = 0; j < track.rotation.Length; j++)
{
switch (header.key_format)
{
case AnimationCompressionFormat.None:
case AnimationCompressionFormat.Float96NoW:
var fvec = new FVector();
if ((header.component_mask & 7) != 0)
{
if ((header.component_mask & 1) != 0) fvec.X = reader.ReadSingle();
if ((header.component_mask & 2) != 0) fvec.Y = reader.ReadSingle();
if ((header.component_mask & 4) != 0) fvec.Z = reader.ReadSingle();
}
else
{
fvec = new FVector(reader);
}
var fquat = new FQuat()
{
X = fvec.X,
Y = fvec.Y,
Z = fvec.Z
};
fquat.rebuild_w();
track.rotation[j] = fquat;
break;
case AnimationCompressionFormat.Fixed48NoW:
fquat = new FQuat();
if ((header.component_mask & 1) != 0) fquat.X = read_fixed48_q(reader.ReadUInt16());
if ((header.component_mask & 2) != 0) fquat.Y = read_fixed48_q(reader.ReadUInt16());
if ((header.component_mask & 4) != 0) fquat.Z = read_fixed48_q(reader.ReadUInt16());
fquat.rebuild_w();
track.rotation[j] = fquat;
break;
case AnimationCompressionFormat.IntervalFixed32NoW:
track.rotation[j] = read_fixed32_quat(reader.ReadUInt32(), min, max);
break;
}
}
if (header.has_time_tracks)
{
track.rotation_times = read_times(reader, header.num_keys, (uint)num_frames);
}
align_reader(reader);
}
// scale
offset = compressed_scale_offsets.offset_data[i * compressed_scale_offsets.strip_size];
if (offset != -1)
{
var header = new FAnimKeyHeader(reader);
var min = new FVector();
var max = new FVector();
if (header.key_format == AnimationCompressionFormat.IntervalFixed32NoW)
{
if ((header.component_mask & 1) != 0)
{
min.X = reader.ReadSingle();
max.X = reader.ReadSingle();
}
if ((header.component_mask & 2) != 0)
{
min.Y = reader.ReadSingle();
max.Y = reader.ReadSingle();
}
if ((header.component_mask & 4) != 0)
{
min.Z = reader.ReadSingle();
max.Z = reader.ReadSingle();
}
}
track.scale = new FVector[header.num_keys];
for (int j = 0; j < track.scale.Length; j++)
{
switch (header.key_format)
{
case AnimationCompressionFormat.None:
case AnimationCompressionFormat.Float96NoW:
var fvec = new FVector();
if ((header.component_mask & 7) != 0)
{
if ((header.component_mask & 1) != 0) fvec.X = reader.ReadSingle();
if ((header.component_mask & 2) != 0) fvec.Y = reader.ReadSingle();
if ((header.component_mask & 4) != 0) fvec.Z = reader.ReadSingle();
}
else
{
fvec = new FVector(reader);
}
track.scale[j] = fvec;
break;
case AnimationCompressionFormat.Fixed48NoW:
fvec = new FVector();
if ((header.component_mask & 1) != 0) fvec.X = read_fixed48(reader.ReadUInt16());
if ((header.component_mask & 2) != 0) fvec.Y = read_fixed48(reader.ReadUInt16());
if ((header.component_mask & 4) != 0) fvec.Z = read_fixed48(reader.ReadUInt16());
track.scale[j] = fvec;
break;
case AnimationCompressionFormat.IntervalFixed32NoW:
track.scale[j] = read_fixed32_vec(reader.ReadUInt32(), min, max);
break;
}
}
if (header.has_time_tracks)
{
track.scale_times = read_times(reader, header.num_keys, (uint)num_frames);
}
align_reader(reader);
}
ret[i] = track;
}
if (reader.BaseStream.Position != stream.Length)
{
throw new FileLoadException($"Could not read tracks correctly, {reader.BaseStream.Position - stream.Length} bytes remaining");
}
return ret;
}
}
}
}

View File

@ -0,0 +1,9 @@
namespace PakReader
{
public enum ECurveTableMode : byte
{
Empty,
SimpleCurves,
RichCurves,
}
}

View File

@ -0,0 +1,42 @@
using System;
using System.IO;
using static PakReader.AssetReader;
namespace PakReader
{
public sealed class UCurveTable : ExportObject
{
public UObject super_object;
public ECurveTableMode curve_table_mode;
public (string Name, UObject Object)[] row_map;
internal UCurveTable(BinaryReader reader, FNameEntrySerialized[] name_map, FObjectImport[] import_map)
{
super_object = new UObject(reader, name_map, import_map, "CurveTable", true);
row_map = new (string Name, UObject Object)[reader.ReadInt32()];
curve_table_mode = (ECurveTableMode)reader.ReadByte();
string row_type;
switch (curve_table_mode)
{
case ECurveTableMode.Empty:
row_type = "Empty";
break;
case ECurveTableMode.SimpleCurves:
row_type = "SimpleCurveKey";
break;
case ECurveTableMode.RichCurves:
row_type = "RichCurveKey";
break;
default:
throw new InvalidOperationException("Unsupported curve mode " + (byte)curve_table_mode);
}
for (int i = 0; i < row_map.Length; i++)
{
row_map[i] = (read_fname(reader, name_map), new UObject(reader, name_map, import_map, row_type, false));
}
}
}
}

View File

@ -0,0 +1,23 @@
using System.IO;
using static PakReader.AssetReader;
namespace PakReader
{
public sealed class UDataTable : ExportObject
{
public UObject super_object;
public (string Name, UObject Object)[] rows;
internal UDataTable(BinaryReader reader, FNameEntrySerialized[] name_map, FObjectImport[] import_map)
{
super_object = new UObject(reader, name_map, import_map, "RowStruct", true);
rows = new (string Name, UObject Object)[reader.ReadInt32()];
for (int i = 0; i < rows.Length; i++)
{
rows[i] = (read_fname(reader, name_map), new UObject(reader, name_map, import_map, "RowStruct", false));
}
}
}
}

View File

@ -0,0 +1,35 @@
using System.Collections.Generic;
using System.IO;
using static PakReader.AssetReader;
namespace PakReader
{
public class UObject : ExportObject
{
public string export_type;
public FPropertyTag[] properties;
internal UObject(BinaryReader reader, FNameEntrySerialized[] name_map, FObjectImport[] import_map, string export_type, bool read_guid)
{
this.export_type = export_type;
var properties_ = new List<FPropertyTag>();
while (true)
{
var tag = read_property_tag(reader, name_map, import_map, export_type != "FontFace");
if (tag.Equals(default))
{
break;
}
properties_.Add(tag);
}
if (read_guid && reader.ReadUInt32() != 0)
{
if (reader.BaseStream.Position + 16 <= reader.BaseStream.Length)
new FGuid(reader);
}
properties = properties_.ToArray();
}
}
}

View File

@ -0,0 +1,48 @@
using System.IO;
using static PakReader.AssetReader;
namespace PakReader
{
public struct UScriptArray
{
public FPropertyTag tag;
public object[] data;
internal UScriptArray(BinaryReader reader, string inner_type, FNameEntrySerialized[] name_map, FObjectImport[] import_map)
{
uint element_count = reader.ReadUInt32();
tag = default;
if (inner_type == "StructProperty" || inner_type == "ArrayProperty")
{
tag = read_property_tag(reader, name_map, import_map, false);
if (tag.Equals(default))
{
throw new IOException("Could not read file");
}
}
object inner_tag_data = tag.Equals(default) ? null : tag.tag_data;
data = new object[element_count];
for (int i = 0; i < element_count; i++)
{
if (inner_type == "BoolProperty")
{
data[i] = reader.ReadByte() != 0;
}
else if (inner_type == "ByteProperty")
{
data[i] = reader.ReadByte();
}
else
{
var tag = new_property_tag_type(reader, name_map, import_map, inner_type, inner_tag_data);
if ((int)tag.type != 100)
{
data[i] = tag.data;
}
}
}
}
}
}

View File

@ -0,0 +1,28 @@
using System;
using System.Collections.Generic;
using System.IO;
using static PakReader.AssetReader;
namespace PakReader
{
public struct UScriptMap
{
public Dictionary<object, object> map_data;
internal UScriptMap(BinaryReader reader, FNameEntrySerialized[] name_map, FObjectImport[] import_map, string key_type, string value_type)
{
int num_keys_to_remove = reader.ReadInt32();
if (num_keys_to_remove != 0)
{
throw new NotSupportedException($"Could not read MapProperty with types: {key_type} {value_type}");
}
int num = reader.ReadInt32();
map_data = new Dictionary<object, object>(num);
for (int i = 0; i < num; i++)
{
map_data[read_map_value(reader, key_type, "StructProperty", name_map, import_map)] = read_map_value(reader, value_type, "StructProperty", name_map, import_map);
}
}
}
}

View File

@ -0,0 +1,32 @@
using System.IO;
namespace PakReader
{
public struct FAnimKeyHeader
{
public AnimationCompressionFormat key_format;
public uint component_mask;
public uint num_keys;
public bool has_time_tracks;
public FAnimKeyHeader(BinaryReader reader)
{
var packed = reader.ReadUInt32();
key_format = (AnimationCompressionFormat)(packed >> 28);
component_mask = (packed >> 24) & 0xF;
num_keys = packed & 0xFFFFFF;
has_time_tracks = (component_mask & 8) != 0;
}
}
public enum AnimationCompressionFormat : uint
{
None,
Float96NoW,
Fixed48NoW,
IntervalFixed32NoW,
Fixed32NoW,
Float32NoW,
Identity,
}
}

View File

@ -0,0 +1,18 @@
using System.IO;
namespace PakReader
{
public struct FBoxSphereBounds
{
public FVector origin;
public FVector box_extend;
public float sphere_radius;
internal FBoxSphereBounds(BinaryReader reader)
{
origin = new FVector(reader);
box_extend = new FVector(reader);
sphere_radius = reader.ReadSingle();
}
}
}

View File

@ -0,0 +1,36 @@
using System.IO;
namespace PakReader
{
public struct FByteBulkData
{
public FByteBulkDataHeader header;
public byte[] data;
internal FByteBulkData(BinaryReader reader, BinaryReader ubulk, long bulk_offset)
{
header = new FByteBulkDataHeader(reader);
data = null;
if ((header.bulk_data_flags & 0x0040) != 0)
{
data = reader.ReadBytes(header.element_count);
}
if ((header.bulk_data_flags & 0x0100) != 0)
{
if (ubulk == null)
{
throw new IOException("No ubulk specified");
}
// Archive seems "kind of" appended.
ubulk.BaseStream.Seek(header.offset_in_file + bulk_offset, SeekOrigin.Begin);
data = ubulk.ReadBytes(header.element_count);
}
if (data == null)
{
throw new IOException("Could not read data");
}
}
}
}

View File

@ -0,0 +1,20 @@
using System.IO;
namespace PakReader
{
public struct FByteBulkDataHeader
{
public int bulk_data_flags;
public int element_count;
public int size_on_disk;
public long offset_in_file;
internal FByteBulkDataHeader(BinaryReader reader)
{
bulk_data_flags = reader.ReadInt32();
element_count = reader.ReadInt32();
size_on_disk = reader.ReadInt32();
offset_in_file = reader.ReadInt64();
}
}
}

View File

@ -0,0 +1,27 @@
using Newtonsoft.Json;
using System.IO;
using static PakReader.AssetReader;
namespace PakReader
{
public struct FColor
{
public byte r;
public byte g;
public byte b;
public byte a;
[JsonProperty]
public string Hex => a == 0 || a == 255 ?
ToHex(r, g, b) :
ToHex(r, g, b, a);
internal FColor(BinaryReader reader)
{
r = reader.ReadByte();
g = reader.ReadByte();
b = reader.ReadByte();
a = reader.ReadByte();
}
}
}

View File

@ -0,0 +1,8 @@
namespace PakReader
{
public struct FCompressedOffsetData
{
public int[] offset_data;
public int strip_size;
}
}

View File

@ -0,0 +1,24 @@
using System.IO;
namespace PakReader
{
public struct FCompressedSegment
{
public int start_frame;
public int num_frames;
public int byte_stream_offset;
public byte translation_compression_format;
public byte rotation_compression_format;
public byte scale_compression_format;
public FCompressedSegment(BinaryReader reader)
{
start_frame = reader.ReadInt32();
num_frames = reader.ReadInt32();
byte_stream_offset = reader.ReadInt32();
translation_compression_format = reader.ReadByte();
rotation_compression_format = reader.ReadByte();
scale_compression_format = reader.ReadByte();
}
}
}

View File

@ -0,0 +1,14 @@
using System.IO;
namespace PakReader
{
internal struct FDateTime
{
public long date;
public FDateTime(BinaryReader reader)
{
date = reader.ReadInt64();
}
}
}

View File

@ -0,0 +1,21 @@
using System.IO;
using static PakReader.AssetReader;
namespace PakReader
{
public struct FGameplayTagContainer
{
public string[] gameplay_tags;
internal FGameplayTagContainer(BinaryReader reader, FNameEntrySerialized[] name_map)
{
uint length = reader.ReadUInt32();
gameplay_tags = new string[length];
for (int i = 0; i < length; i++)
{
gameplay_tags[i] = read_fname(reader, name_map);
}
}
}
}

View File

@ -0,0 +1,41 @@
using System.IO;
namespace PakReader
{
public struct FGuid
{
public uint A, B, C, D;
public FGuid(BinaryReader reader)
{
A = reader.ReadUInt32();
B = reader.ReadUInt32();
C = reader.ReadUInt32();
D = reader.ReadUInt32();
}
public override bool Equals(object obj) => obj is FGuid ? this == (FGuid)obj : false;
public override int GetHashCode()
{
return (int)(((long)A + B + C + D) % uint.MaxValue - int.MaxValue);
}
public override string ToString()
{
return $"{A}-{B}-{C}-{D}";
}
public static bool operator ==(FGuid a, FGuid b) =>
a.A == b.A &&
a.B == b.B &&
a.C == b.C &&
a.D == b.D;
public static bool operator !=(FGuid a, FGuid b) =>
a.A != b.A ||
a.B != b.B ||
a.C != b.C ||
a.D != b.D;
}
}

View File

@ -0,0 +1,16 @@
using System.IO;
namespace PakReader
{
public struct FIntPoint
{
public uint x;
public uint y;
internal FIntPoint(BinaryReader reader)
{
x = reader.ReadUInt32();
y = reader.ReadUInt32();
}
}
}

View File

@ -0,0 +1,19 @@
using System.IO;
using static PakReader.AssetReader;
namespace PakReader
{
internal struct FLevelSequenceLegacyObjectReference
{
public FGuid key_guid;
public FGuid object_id;
public string object_path;
internal FLevelSequenceLegacyObjectReference(BinaryReader reader)
{
key_guid = new FGuid(reader);
object_id = new FGuid(reader);
object_path = read_string(reader);
}
}
}

View File

@ -0,0 +1,19 @@
using System.IO;
namespace PakReader
{
internal struct FLevelSequenceObjectReferenceMap
{
public FLevelSequenceLegacyObjectReference[] map_data;
internal FLevelSequenceObjectReferenceMap(BinaryReader reader)
{
int element_count = reader.ReadInt32();
map_data = new FLevelSequenceLegacyObjectReference[element_count];
for (int i = 0; i < element_count; i++)
{
map_data[i] = new FLevelSequenceLegacyObjectReference(reader);
}
}
}
}

View File

@ -0,0 +1,28 @@
using Newtonsoft.Json;
using System;
using System.IO;
using static PakReader.AssetReader;
namespace PakReader
{
public struct FLinearColor
{
public float r;
public float g;
public float b;
public float a;
[JsonProperty]
public string Hex => a == 1 || a == 0 ?
ToHex((byte)Math.Round(r * 256), (byte)Math.Round(g * 256), (byte)Math.Round(b * 256)) :
ToHex((byte)Math.Round(r * 256), (byte)Math.Round(g * 256), (byte)Math.Round(b * 256), (byte)Math.Round(a * 256));
internal FLinearColor(BinaryReader reader)
{
r = reader.ReadSingle();
g = reader.ReadSingle();
b = reader.ReadSingle();
a = reader.ReadSingle();
}
}
}

View File

@ -0,0 +1,19 @@
using System.IO;
using static PakReader.AssetReader;
namespace PakReader
{
internal struct FNameEntrySerialized
{
public string data;
public ushort non_case_preserving_hash;
public ushort case_preserving_hash;
internal FNameEntrySerialized(BinaryReader reader)
{
data = read_string(reader);
non_case_preserving_hash = reader.ReadUInt16();
case_preserving_hash = reader.ReadUInt16();
}
}
}

View File

@ -0,0 +1,53 @@
using System.IO;
using static PakReader.AssetReader;
namespace PakReader
{
public struct FObjectExport
{
public FPackageIndex class_index;
public FPackageIndex super_index;
public FPackageIndex template_index;
public FPackageIndex outer_index;
public string object_name;
public uint save;
public long serial_size;
public long serial_offset;
public bool forced_export;
public bool not_for_client;
public bool not_for_server;
public FGuid package_guid;
public uint package_flags;
public bool not_always_loaded_for_editor_game;
public bool is_asset;
public int first_export_dependency;
public bool serialization_before_serialization_dependencies;
public bool create_before_serialization_dependencies;
public bool serialization_before_create_dependencies;
public bool create_before_create_dependencies;
internal FObjectExport(BinaryReader reader, FNameEntrySerialized[] name_map, FObjectImport[] import_map)
{
class_index = new FPackageIndex(reader, import_map);
super_index = new FPackageIndex(reader, import_map);
template_index = new FPackageIndex(reader, import_map);
outer_index = new FPackageIndex(reader, import_map);
object_name = read_fname(reader, name_map);
save = reader.ReadUInt32();
serial_size = reader.ReadInt64();
serial_offset = reader.ReadInt64();
forced_export = reader.ReadInt32() != 0;
not_for_client = reader.ReadInt32() != 0;
not_for_server = reader.ReadInt32() != 0;
package_guid = new FGuid(reader);
package_flags = reader.ReadUInt32();
not_always_loaded_for_editor_game = reader.ReadInt32() != 0;
is_asset = reader.ReadInt32() != 0;
first_export_dependency = reader.ReadInt32();
serialization_before_serialization_dependencies = reader.ReadInt32() != 0;
create_before_serialization_dependencies = reader.ReadInt32() != 0;
serialization_before_create_dependencies = reader.ReadInt32() != 0;
create_before_create_dependencies = reader.ReadInt32() != 0;
}
}
}

View File

@ -0,0 +1,21 @@
using System.IO;
using static PakReader.AssetReader;
namespace PakReader
{
public struct FObjectImport
{
public string class_package;
public string class_name;
public FPackageIndex outer_index;
public string object_name;
internal FObjectImport(BinaryReader reader, FNameEntrySerialized[] name_map, FObjectImport[] import_map)
{
class_package = read_fname(reader, name_map);
class_name = read_fname(reader, name_map);
outer_index = new FPackageIndex(reader, import_map);
object_name = read_fname(reader, name_map);
}
}
}

View File

@ -0,0 +1,31 @@
using Newtonsoft.Json;
using System.IO;
namespace PakReader
{
public class FPackageIndex
{
[JsonIgnore]
public int index;
public string import;
public string outer_import;
internal FPackageIndex(BinaryReader reader, FObjectImport[] import_map)
{
index = reader.ReadInt32();
if (index < 0) index *= -1;
index -= 1;
if (index < 0 || index >= import_map.Length)
{
import = index.ToString();
outer_import = default;
}
else
{
var imp = import_map[index];
import = imp.object_name;
outer_import = imp.outer_index?.import;
}
}
}
}

View File

@ -0,0 +1,32 @@
using Newtonsoft.Json;
namespace PakReader
{
public struct FPropertyTag
{
public string name;
public long position;
[JsonIgnore]
public string property_type;
public object tag_data;
[JsonIgnore]
public int size;
[JsonIgnore]
public int array_index;
[JsonIgnore]
public FGuid property_guid;
[JsonIgnore]
public FPropertyTagType tag;
public bool Equals(FPropertyTag b)
{
return name == b.name &&
position == b.position &&
property_type == b.property_type &&
size == b.size &&
array_index == b.array_index &&
tag == b.tag &&
tag_data == b.tag_data;
}
}
}

View File

@ -0,0 +1,25 @@
namespace PakReader
{
public enum FPropertyTagType
{
BoolProperty,
StructProperty,
ObjectProperty,
InterfaceProperty,
FloatProperty,
TextProperty,
StrProperty,
NameProperty,
IntProperty,
UInt16Property,
UInt32Property,
UInt64Property,
ArrayProperty,
MapProperty,
ByteProperty,
EnumProperty,
DelegateProperty,
SoftObjectProperty,
SoftObjectPropertyMap,
}
}

View File

@ -0,0 +1,51 @@
using System;
using System.IO;
namespace PakReader
{
public struct FQuat
{
public float X;
public float Y;
public float Z;
public float W;
internal FQuat(BinaryReader reader)
{
X = reader.ReadSingle();
Y = reader.ReadSingle();
Z = reader.ReadSingle();
W = reader.ReadSingle();
}
public void rebuild_w()
{
var ww = 1f - (X * X + Y * Y + Z * Z);
W = ww > 0 ? (float)Math.Sqrt(ww) : 0;
}
public static implicit operator CQuat(FQuat me) => new CQuat
{
x = me.X,
y = me.Y,
z = me.Z,
w = me.W
};
public static implicit operator FQuat(CQuat me) => new FQuat
{
X = me.x,
Y = me.y,
Z = me.z,
W = me.w
};
public void Write(BinaryWriter writer)
{
writer.Write(X);
writer.Write(Y);
writer.Write(Z);
writer.Write(W);
}
}
}

View File

@ -0,0 +1,17 @@
using System.IO;
using static PakReader.AssetReader;
namespace PakReader
{
public struct FReferencePose
{
public string pose_name;
public FTransform[] reference_pose;
internal FReferencePose(BinaryReader reader, FNameEntrySerialized[] name_map)
{
pose_name = read_fname(reader, name_map);
reference_pose = reader.ReadTArray(() => new FTransform(reader));
}
}
}

View File

@ -0,0 +1,17 @@
using System.IO;
using static PakReader.AssetReader;
namespace PakReader
{
public struct FMeshBoneInfo
{
public string name;
public int parent_index;
internal FMeshBoneInfo(BinaryReader reader, FNameEntrySerialized[] name_map)
{
name = read_fname(reader, name_map);
parent_index = reader.ReadInt32();
}
}
}

View File

@ -0,0 +1,24 @@
using System.IO;
using static PakReader.AssetReader;
namespace PakReader
{
public struct FReferenceSkeleton
{
public FMeshBoneInfo[] ref_bone_info;
public FTransform[] ref_bone_pose;
public (string, int)[] name_to_index;
internal FReferenceSkeleton(BinaryReader reader, FNameEntrySerialized[] name_map)
{
ref_bone_info = reader.ReadTArray(() => new FMeshBoneInfo(reader, name_map));
ref_bone_pose = reader.ReadTArray(() => new FTransform(reader));
name_to_index = new (string, int)[reader.ReadUInt32()];
for (int i = 0; i < name_to_index.Length; i++)
{
name_to_index[i] = (read_fname(reader, name_map), reader.ReadInt32());
}
}
}
}

View File

@ -0,0 +1,18 @@
using System.IO;
namespace PakReader
{
public struct FTransform
{
public FQuat rotation;
public FVector translation;
public FVector scale_3d;
internal FTransform(BinaryReader reader)
{
rotation = new FQuat(reader);
translation = new FVector(reader);
scale_3d = new FVector(reader);
}
}
}

View File

@ -0,0 +1,28 @@
using System.IO;
namespace PakReader
{
internal struct FRichCurveKey
{
public byte interp_mode;
public byte tangent_mode;
public byte tangent_weight_mode;
public float time;
public float arrive_tangent;
public float arrive_tangent_weight;
public float leave_tangent;
public float leave_tangent_weight;
public FRichCurveKey(BinaryReader reader)
{
interp_mode = reader.ReadByte();
tangent_mode = reader.ReadByte();
tangent_weight_mode = reader.ReadByte();
time = reader.ReadSingle();
arrive_tangent = reader.ReadSingle();
arrive_tangent_weight = reader.ReadSingle();
leave_tangent = reader.ReadSingle();
leave_tangent_weight = reader.ReadSingle();
}
}
}

View File

@ -0,0 +1,18 @@
using System.IO;
namespace PakReader
{
public struct FRotator
{
public float pitch;
public float yaw;
public float roll;
internal FRotator(BinaryReader reader)
{
pitch = reader.ReadSingle();
yaw = reader.ReadSingle();
roll = reader.ReadSingle();
}
}
}

View File

@ -0,0 +1,17 @@
using System.IO;
using static PakReader.AssetReader;
namespace PakReader
{
public struct FScriptDelegate
{
public int obj;
public string name;
internal FScriptDelegate(BinaryReader reader, FNameEntrySerialized[] name_map)
{
obj = reader.ReadInt32();
name = read_fname(reader, name_map);
}
}
}

View File

@ -0,0 +1,16 @@
using System.IO;
namespace PakReader
{
internal struct FSimpleCurveKey
{
public float time;
public float value;
public FSimpleCurveKey(BinaryReader reader)
{
time = reader.ReadSingle();
value = reader.ReadSingle();
}
}
}

View File

@ -0,0 +1,22 @@
using System.IO;
namespace PakReader
{
public struct FMeshUVChannelInfo
{
public bool initialized;
public bool override_densities;
public float[] local_uv_densities;
internal FMeshUVChannelInfo(BinaryReader reader)
{
initialized = reader.ReadUInt32() != 0;
override_densities = reader.ReadUInt32() != 0;
local_uv_densities = new float[4];
for (int i = 0; i < 4; i++)
{
local_uv_densities[i] = reader.ReadSingle();
}
}
}
}

View File

@ -0,0 +1,25 @@
using System.IO;
using static PakReader.AssetReader;
namespace PakReader
{
public struct FSkeletalMaterial
{
public FPackageIndex Material;
public string MaterialSlotName;
public FMeshUVChannelInfo UVChannelData;
internal FSkeletalMaterial(BinaryReader reader, FNameEntrySerialized[] name_map, FObjectImport[] import_map)
{
Material = new FPackageIndex(reader, import_map);
MaterialSlotName = read_fname(reader, name_map);
bool bSerializeImportedMaterialSlotName = reader.ReadUInt32() != 0;
if (bSerializeImportedMaterialSlotName)
{
var ImportedMaterialSlotName = read_fname(reader, name_map);
}
UVChannelData = new FMeshUVChannelInfo(reader);
}
}
}

View File

@ -0,0 +1,10 @@
namespace PakReader
{
public struct FSkeletalMeshLODInfo
{
public float DisplayFactor;
public float LODHysteresis;
public int[] LODMaterialMap;
public bool[] bEnableShadowCasting;
}
}

View File

@ -0,0 +1,15 @@
using System.IO;
using static PakReader.AssetReader;
namespace PakReader
{
public struct FSmartName
{
public string display_name;
internal FSmartName(BinaryReader reader, FNameEntrySerialized[] name_map)
{
display_name = read_fname(reader, name_map);
}
}
}

View File

@ -0,0 +1,17 @@
using System.IO;
using static PakReader.AssetReader;
namespace PakReader
{
public struct FSoftObjectPath
{
public string asset_path_name;
public string sub_path_string;
internal FSoftObjectPath(BinaryReader reader, FNameEntrySerialized[] name_map)
{
asset_path_name = read_fname(reader, name_map);
sub_path_string = read_string(reader);
}
}
}

View File

@ -0,0 +1,17 @@
using System.IO;
using static PakReader.AssetReader;
namespace PakReader
{
public struct FSoftObjectPathMap
{
public string asset_path_name;
public string sub_path_string;
internal FSoftObjectPathMap(BinaryReader reader, FNameEntrySerialized[] name_map)
{
asset_path_name = read_fname(reader, name_map);
sub_path_string = read_string(reader);
}
}
}

View File

@ -0,0 +1,17 @@
using System.IO;
using static PakReader.AssetReader;
namespace PakReader
{
public class FSoundFormatData
{
public string name;
public FByteBulkData data;
internal FSoundFormatData(BinaryReader reader, FNameEntrySerialized[] name_map, int asset_file_size, long export_size, BinaryReader ubulk)
{
name = read_fname(reader, name_map);
data = new FByteBulkData(reader, ubulk, export_size + asset_file_size);
}
}
}

View File

@ -0,0 +1,24 @@
using System.IO;
namespace PakReader
{
public struct FColorVertexBuffer
{
public int stride;
public int num_verts;
public FColor[] colors;
public FColorVertexBuffer(BinaryReader reader)
{
var flags = new FStripDataFlags(reader);
stride = reader.ReadInt32();
num_verts = reader.ReadInt32();
colors = null;
if (!flags.server_data_stripped && num_verts > 0)
{
var _element_size = reader.ReadInt32();
colors = reader.ReadTArray(() => new FColor(reader));
}
}
}
}

View File

@ -0,0 +1,29 @@
using System.IO;
namespace PakReader
{
public struct FMultisizeIndexContainer
{
public ushort[] Indices16;
public uint[] Indices32;
public FMultisizeIndexContainer(BinaryReader reader)
{
var data_size = reader.ReadByte();
var _element_size = reader.ReadInt32();
switch (data_size)
{
case 2:
Indices16 = reader.ReadTArray(() => reader.ReadUInt16());
Indices32 = null;
return;
case 4:
Indices32 = reader.ReadTArray(() => reader.ReadUInt32());
Indices16 = null;
return;
default:
throw new FileLoadException("No format size");
}
}
}
}

View File

@ -0,0 +1,19 @@
using System.IO;
namespace PakReader
{
public struct FPositionVertexBuffer
{
public FVector[] verts;
public int stride;
public int num_verts;
public FPositionVertexBuffer(BinaryReader reader)
{
stride = reader.ReadInt32();
num_verts = reader.ReadInt32();
var _element_size = reader.ReadInt32();
verts = reader.ReadTArray(() => new FVector(reader));
}
}
}

View File

@ -0,0 +1,22 @@
using System.IO;
namespace PakReader
{
public struct FApexClothPhysToRenderVertData
{
public FVector4 PositionBaryCoordsAndDist;
public FVector4 NormalBaryCoordsAndDist;
public FVector4 TangentBaryCoordsAndDist;
public short[] SimulMeshVertIndices;
public int[] Padding;
public FApexClothPhysToRenderVertData(BinaryReader reader)
{
PositionBaryCoordsAndDist = new FVector4(reader);
NormalBaryCoordsAndDist = new FVector4(reader);
TangentBaryCoordsAndDist = new FVector4(reader);
SimulMeshVertIndices = new short[] { reader.ReadInt16(), reader.ReadInt16(), reader.ReadInt16(), reader.ReadInt16() };
Padding = new int[] { reader.ReadInt32(), reader.ReadInt32() };
}
}
}

View File

@ -0,0 +1,16 @@
using System.IO;
namespace PakReader
{
public struct FClothingSectionData
{
public FGuid asset_guid;
public int asset_lod_index;
public FClothingSectionData(BinaryReader reader)
{
asset_guid = new FGuid(reader);
asset_lod_index = reader.ReadInt32();
}
}
}

View File

@ -0,0 +1,16 @@
using System.IO;
namespace PakReader
{
public struct FDuplicatedVerticesBuffer
{
public int[] dup_vert;
public FIndexLengthPair[] dup_vert_index;
public FDuplicatedVerticesBuffer(BinaryReader reader)
{
dup_vert = reader.ReadTArray(() => reader.ReadInt32());
dup_vert_index = reader.ReadTArray(() => new FIndexLengthPair(reader));
}
}
}

View File

@ -0,0 +1,16 @@
using System.IO;
namespace PakReader
{
public struct FIndexLengthPair
{
public uint word1;
public uint word2;
public FIndexLengthPair(BinaryReader reader)
{
word1 = reader.ReadUInt32();
word2 = reader.ReadUInt32();
}
}
}

View File

@ -0,0 +1,40 @@
using System.IO;
namespace PakReader
{
public struct FSkelMeshSection
{
public ushort material_index;
public uint base_index;
public uint num_triangles;
public uint base_vertex_index;
public FApexClothPhysToRenderVertData[] cloth_mapping_data;
public ushort[] bone_map;
public int num_vertices;
public int max_bone_influences;
public FClothingSectionData clothing_data;
public bool disabled;
internal FSkelMeshSection(BinaryReader reader, FNameEntrySerialized[] name_map)
{
var flags = new FStripDataFlags(reader);
material_index = reader.ReadUInt16();
base_index = reader.ReadUInt32();
num_triangles = reader.ReadUInt32();
var _recompute_tangent = reader.ReadUInt32() != 0;
var _cast_shadow = reader.ReadUInt32() != 0;
base_vertex_index = reader.ReadUInt32();
cloth_mapping_data = reader.ReadTArray(() => new FApexClothPhysToRenderVertData(reader));
bool HasClothData = cloth_mapping_data.Length > 0;
bone_map = reader.ReadTArray(() => reader.ReadUInt16());
num_vertices = reader.ReadInt32();
max_bone_influences = reader.ReadInt32();
var _correspond_cloth_asset_index = reader.ReadInt16();
clothing_data = new FClothingSectionData(reader);
var _vertex_buffer = new FDuplicatedVerticesBuffer(reader);
disabled = reader.ReadUInt32() != 0;
}
}
}

View File

@ -0,0 +1,11 @@
namespace PakReader
{
public struct FGPUVert4Float
{
public FVector Pos;
public FPackedNormal[] Normal; // 3 length
public FSkinWeightInfo Infs;
public FMeshUVFloat[] UV; // 4 length
}
}

View File

@ -0,0 +1,11 @@
namespace PakReader
{
public struct FGPUVert4Half
{
public FVector Pos;
public FPackedNormal[] Normal; // 3 length
public FSkinWeightInfo Infs;
public FMeshUVHalf[] UV; // 4 length
}
}

View File

@ -0,0 +1,25 @@
using System.IO;
namespace PakReader
{
public struct FMeshUVFloat
{
public float U;
public float V;
public FMeshUVFloat(BinaryReader reader)
{
U = reader.ReadSingle();
V = reader.ReadSingle();
}
public static implicit operator CMeshUVFloat(FMeshUVFloat me)
{
return new CMeshUVFloat
{
U = me.U,
V = me.V
};
}
}
}

View File

@ -0,0 +1,25 @@
using System.IO;
namespace PakReader
{
public struct FMeshUVHalf
{
public ushort U;
public ushort V;
public FMeshUVHalf(BinaryReader reader)
{
U = reader.ReadUInt16();
V = reader.ReadUInt16();
}
public static explicit operator FMeshUVFloat(FMeshUVHalf me)
{
return new FMeshUVFloat
{
U = Extensions.HalfToFloat(me.U),
V = Extensions.HalfToFloat(me.V)
};
}
}
}

View File

@ -0,0 +1,35 @@
using System.IO;
namespace PakReader
{
public struct FPackedNormal
{
public uint Data;
public FPackedNormal(BinaryReader reader)
{
Data = reader.ReadUInt32();
Data ^= 0x80808080; // 4.20+: https://github.com/gildor2/UModel/blob/dcdb92c987c15f0a5d3366247667a8fb9fd8008b/Unreal/UnCore.h#L1216
}
public static implicit operator FPackedNormal(FVector V) => new FPackedNormal
{
Data = (uint)((int)((V.X + 1) * 127.5f)
+ ((int)((V.Y + 1) * 127.5f) << 8)
+ ((int)((V.Z + 1) * 127.5f) << 16))
};
public static implicit operator FPackedNormal(FVector4 V) => new FPackedNormal
{
Data = (uint)((int)((V.X + 1) * 127.5f)
+ ((int)((V.Y + 1) * 127.5f) << 8)
+ ((int)((V.Z + 1) * 127.5f) << 16)
+ ((int)((V.W + 1) * 127.5f) << 24))
};
public static implicit operator FPackedNormal(CPackedNormal me) => new FPackedNormal
{
Data = me.Data ^ 0x80808080
};
}
}

View File

@ -0,0 +1,26 @@
namespace PakReader
{
public struct FSkeletalMeshVertexBuffer
{
public int NumTexCoords;
public FVector MeshExtension;
public FVector MeshOrigin;
public bool bUseFullPrecisionUVs;
public bool bExtraBoneInfluences;
public FGPUVert4Half[] VertsHalf;
public FGPUVert4Float[] VertsFloat;
public int GetVertexCount()
{
if (VertsHalf != null && VertsHalf.Length != 0)
{
return VertsHalf.Length;
}
else if (VertsFloat != null && VertsFloat.Length != 0)
{
return VertsFloat.Length;
}
return 0;
}
}
}

View File

@ -0,0 +1,30 @@
using System.IO;
namespace PakReader
{
public struct FSkeletalMeshVertexClothBuffer
{
public ulong[] cloth_index_mapping;
public FSkeletalMeshVertexClothBuffer(BinaryReader reader)
{
var flags = new FStripDataFlags(reader);
if (!flags.server_data_stripped)
{
// umodel: https://github.com/gildor2/UModel/blob/9a1fe8c77d136f018ba18c9e5c445fdcc5f374ae/Unreal/UnMesh4.cpp#L924
// https://github.com/gildor2/UModel/blob/39c635c13d61616297fb3e47f33e3fc20259626e/Unreal/UnCoreSerialize.cpp#L320
// ue4: https://github.com/EpicGames/UnrealEngine/blob/master/Engine/Source/Runtime/Engine/Private/SkeletalMeshLODRenderData.cpp#L758
// https://github.com/EpicGames/UnrealEngine/blob/master/Engine/Source/Runtime/Engine/Public/Rendering/SkeletalMeshLODRenderData.h#L119
int elem_size = reader.ReadInt32(); // umodel has this, might want to actually serialize this like how ue4 has it
int count = reader.ReadInt32();
reader.BaseStream.Seek(elem_size * count, SeekOrigin.Current);
cloth_index_mapping = reader.ReadTArray(() => reader.ReadUInt64());
}
cloth_index_mapping = null;
}
}
}

View File

@ -0,0 +1,22 @@
using System.IO;
namespace PakReader
{
public struct FRuntimeSkinWeightProfileData
{
public FSkinWeightOverrideInfo[] overrides_info;
public ushort[] weights;
public (uint, uint)[] vertex_index_override_index;
public FRuntimeSkinWeightProfileData(BinaryReader reader)
{
overrides_info = reader.ReadTArray(() => new FSkinWeightOverrideInfo(reader));
weights = reader.ReadTArray(() => reader.ReadUInt16());
vertex_index_override_index = new (uint, uint)[reader.ReadInt32()];
for (int i = 0; i < vertex_index_override_index.Length; i++)
{
vertex_index_override_index[i] = (reader.ReadUInt32(), reader.ReadUInt32());
}
}
}
}

View File

@ -0,0 +1,16 @@
using System.IO;
namespace PakReader
{
public struct FSkinWeightOverrideInfo
{
public uint influences_offset;
public byte num_influences;
public FSkinWeightOverrideInfo(BinaryReader reader)
{
influences_offset = reader.ReadUInt32();
num_influences = reader.ReadByte();
}
}
}

View File

@ -0,0 +1,19 @@
using System.IO;
using static PakReader.AssetReader;
namespace PakReader
{
public struct FSkinWeightProfilesData
{
public (string, FRuntimeSkinWeightProfileData)[] override_data;
internal FSkinWeightProfilesData(BinaryReader reader, FNameEntrySerialized[] name_map)
{
override_data = new (string, FRuntimeSkinWeightProfileData)[reader.ReadInt32()];
for (int i = 0; i < override_data.Length; i++)
{
override_data[i] = (read_fname(reader, name_map), new FRuntimeSkinWeightProfileData(reader));
}
}
}
}

View File

@ -0,0 +1,16 @@
using System.IO;
namespace PakReader
{
public struct FSkinWeightInfo
{
public byte[] bone_index;
public byte[] bone_weight;
public FSkinWeightInfo(BinaryReader reader, int influences = 4) // NUM_INFLUENCES_UE4 = 4
{
bone_index = reader.ReadBytes(influences);
bone_weight = reader.ReadBytes(influences);
}
}
}

View File

@ -0,0 +1,27 @@
using System.IO;
namespace PakReader
{
public struct FSkinWeightVertexBuffer
{
public FSkinWeightInfo[] weights;
public FSkinWeightVertexBuffer(BinaryReader reader)
{
var flags = new FStripDataFlags(reader);
var bExtraBoneInfluences = reader.ReadInt32() != 0;
var num_vertices = reader.ReadInt32();
if (flags.server_data_stripped)
{
weights = null;
return;
}
var _element_size = reader.ReadInt32();
var num_influences = bExtraBoneInfluences ? 8 : 4;
weights = reader.ReadTArray(() => new FSkinWeightInfo(reader, num_influences));
}
}
}

View File

@ -0,0 +1,86 @@
using System.IO;
namespace PakReader
{
public struct FStaticLODModel
{
public FSkelMeshSection[] Sections;
public FMultisizeIndexContainer Indices;
public FMultisizeIndexContainer AdjacencyIndexBuffer;
public short[] ActiveBoneIndices;
public short[] RequiredBones;
//public FSkelMeshChunk Chunks;
//public int Size;
public int NumVertices;
public int NumTexCoords;
//public FIntBulkData RawPointIndices;
//public int[] MeshToImportVertexMap;
//public int MaxImportVertex;
public FSkeletalMeshVertexBuffer VertexBufferGPUSkin;
//public FSkeletalMeshVertexClothBuffer ColorVertexBuffer;
public FSkeletalMeshVertexClothBuffer ClothVertexBuffer;
public FSkinWeightProfilesData SkinWeightProfilesData;
internal FStaticLODModel(BinaryReader reader, FNameEntrySerialized[] name_map, bool has_vertex_colors)
{
var flags = new FStripDataFlags(reader);
Sections = reader.ReadTArray(() => new FSkelMeshSection(reader, name_map));
Indices = new FMultisizeIndexContainer(reader);
ActiveBoneIndices = reader.ReadTArray(() => reader.ReadInt16());
RequiredBones = reader.ReadTArray(() => reader.ReadInt16());
if (flags.server_data_stripped || flags.class_data_stripped(2))
{
throw new FileLoadException("Could not read FSkelMesh, no renderable data");
}
var position_vertex_buffer = new FPositionVertexBuffer(reader);
var static_mesh_vertex_buffer = new FStaticMeshVertexBuffer(reader);
var skin_weight_vertex_buffer = new FSkinWeightVertexBuffer(reader);
if (has_vertex_colors)
{
var colour_vertex_buffer = new FColorVertexBuffer(reader);
}
AdjacencyIndexBuffer = default;
if (!flags.class_data_stripped(1))
{
AdjacencyIndexBuffer = new FMultisizeIndexContainer(reader);
}
ClothVertexBuffer = default;
if (HasClothData(Sections))
{
ClothVertexBuffer = new FSkeletalMeshVertexClothBuffer(reader);
}
SkinWeightProfilesData = new FSkinWeightProfilesData(reader, name_map);
VertexBufferGPUSkin = new FSkeletalMeshVertexBuffer();
VertexBufferGPUSkin.bUseFullPrecisionUVs = true;
NumVertices = position_vertex_buffer.num_verts;
NumTexCoords = static_mesh_vertex_buffer.num_tex_coords;
VertexBufferGPUSkin.VertsFloat = new FGPUVert4Float[NumVertices];
for (int i = 0; i < NumVertices; i++)
{
var V = new FGPUVert4Float();
var SV = static_mesh_vertex_buffer.uv[i];
V.Pos = position_vertex_buffer.verts[i];
V.Infs = skin_weight_vertex_buffer.weights[i];
V.Normal = SV.Normal; // i mean, we're not using it for anything else, are we?
V.UV = SV.UV;
VertexBufferGPUSkin.VertsFloat[i] = V;
}
}
static bool HasClothData(FSkelMeshSection[] sections)
{
foreach (var s in sections)
if (s.cloth_mapping_data.Length > 0)
return true;
return false;
}
}
}

View File

@ -0,0 +1,32 @@
using System.IO;
namespace PakReader
{
public struct FPackedRGBA16N
{
public ushort X;
public ushort Y;
public ushort Z;
public ushort W;
public FPackedRGBA16N(BinaryReader reader)
{
X = reader.ReadUInt16();
Y = reader.ReadUInt16();
Z = reader.ReadUInt16();
W = reader.ReadUInt16();
X ^= 0x8000; // 4.20+: https://github.com/gildor2/UModel/blob/dcdb92c987c15f0a5d3366247667a8fb9fd8008b/Unreal/UnCore.h#L1290
Y ^= 0x8000;
Z ^= 0x8000;
W ^= 0x8000;
}
public FPackedNormal ToPackedNormal() => new FVector
{
X = (X - 32767.5f) / 32767.5f,
Y = (Y - 32767.5f) / 32767.5f,
Z = (Z - 32767.5f) / 32767.5f
};
}
}

View File

@ -0,0 +1,45 @@
using System.IO;
namespace PakReader
{
public struct FStaticMeshUVItem4
{
public FPackedNormal[] Normal;
public FMeshUVFloat[] UV;
public void SerializeTangents(BinaryReader reader, bool useHighPrecisionTangents)
{
Normal = new FPackedNormal[3];
if (!useHighPrecisionTangents)
{
Normal[0] = new FPackedNormal(reader);
Normal[2] = new FPackedNormal(reader);
}
else
{
FPackedRGBA16N Normal, Tangent;
Normal = new FPackedRGBA16N(reader);
Tangent = new FPackedRGBA16N(reader);
this.Normal[0] = Normal.ToPackedNormal();
this.Normal[2] = Tangent.ToPackedNormal();
}
}
public void SerializeTexcoords(BinaryReader reader, int uvSets, bool useStaticFloatUVs)
{
UV = new FMeshUVFloat[8];
if (useStaticFloatUVs)
{
for (int i = 0; i < uvSets; i++)
UV[i] = new FMeshUVFloat(reader);
}
else
{
for (int i = 0; i < uvSets; i++)
{
UV[i] = (FMeshUVFloat)new FMeshUVHalf(reader);
}
}
}
}
}

View File

@ -0,0 +1,70 @@
using System.IO;
namespace PakReader
{
public struct FStaticMeshVertexBuffer
{
public int num_tex_coords;
public int num_vertices;
bool full_precision_uvs;
bool high_precision_tangent_basis;
public FStaticMeshUVItem4[] uv;
//public FStaticMeshVertexDataUV? uvs;
public FStaticMeshVertexBuffer(BinaryReader reader)
{
high_precision_tangent_basis = false;
var flags = new FStripDataFlags(reader);
num_tex_coords = reader.ReadInt32();
num_vertices = reader.ReadInt32();
full_precision_uvs = reader.ReadInt32() != 0;
high_precision_tangent_basis = reader.ReadInt32() != 0;
if (!flags.server_data_stripped)
{
int ItemSize, ItemCount;
uv = new FStaticMeshUVItem4[num_vertices];
// Tangents
ItemSize = reader.ReadInt32();
ItemCount = reader.ReadInt32();
if (ItemCount != num_vertices)
{
throw new FileLoadException("Invalid item count/num_vertices at pos " + reader.BaseStream.Position);
}
var pos = reader.BaseStream.Position;
for (int i = 0; i < num_vertices; i++)
{
uv[i].SerializeTangents(reader, high_precision_tangent_basis);
}
if (reader.BaseStream.Position - pos != ItemCount * ItemSize)
{
throw new FileLoadException("Didn't read static mesh uvs correctly at pos " + reader.BaseStream.Position);
}
// Texture coordinates
ItemSize = reader.ReadInt32();
ItemCount = reader.ReadInt32();
if (ItemCount != num_vertices * num_tex_coords)
{
throw new FileLoadException("Invalid item count/num_vertices at pos " + reader.BaseStream.Position);
}
pos = reader.BaseStream.Position;
for (int i = 0; i < num_vertices; i++)
{
uv[i].SerializeTexcoords(reader, num_tex_coords, full_precision_uvs);
}
if (reader.BaseStream.Position - pos != ItemCount * ItemSize)
{
throw new FileLoadException("Didn't read static mesh texcoords correctly at pos " + reader.BaseStream.Position);
}
}
else
{
uv = null;
}
}
}
}

View File

@ -0,0 +1,17 @@
using System.IO;
namespace PakReader
{
public struct FVector4
{
public float X, Y, Z, W;
public FVector4(BinaryReader reader)
{
X = reader.ReadSingle();
Y = reader.ReadSingle();
Z = reader.ReadSingle();
W = reader.ReadSingle();
}
}
}

View File

@ -0,0 +1,27 @@
using System.IO;
namespace PakReader
{
public class FStreamedAudioChunk
{
public FByteBulkData data;
public int dataSize;
public int audioDataSize;
internal FStreamedAudioChunk(BinaryReader reader, int asset_file_size, long export_size, BinaryReader ubulk)
{
bool bCooked = reader.ReadInt32() == 1;
if (bCooked)
{
data = new FByteBulkData(reader, ubulk, export_size + asset_file_size);
dataSize = reader.ReadInt32();
audioDataSize = reader.ReadInt32();
}
else
{
reader.BaseStream.Position -= 4;
throw new FileLoadException("StreamedAudioChunks must be cooked");
}
}
}
}

View File

@ -0,0 +1,20 @@
using System.IO;
namespace PakReader
{
internal struct FStripDataFlags
{
byte global_strip_flags;
byte class_strip_flags;
public bool editor_data_stripped => (global_strip_flags & 1) != 0;
public bool server_data_stripped => (global_strip_flags & 2) != 0;
public bool class_data_stripped(byte flag) => (class_strip_flags & flag) != 0;
internal FStripDataFlags(BinaryReader reader)
{
global_strip_flags = reader.ReadByte();
class_strip_flags = reader.ReadByte();
}
}
}

View File

@ -0,0 +1,29 @@
using System.Collections.Generic;
using System.IO;
using static PakReader.AssetReader;
namespace PakReader
{
public struct FStructFallback
{
public FPropertyTag[] properties;
internal FStructFallback(BinaryReader reader, FNameEntrySerialized[] name_map, FObjectImport[] import_map)
{
var properties_ = new List<FPropertyTag>();
int i = 0;
while (true)
{
var tag = read_property_tag(reader, name_map, import_map, true);
if (tag.Equals(default))
{
break;
}
properties_.Add(tag);
i++;
}
properties = properties_.ToArray();
}
}
}

View File

@ -0,0 +1,41 @@
using Newtonsoft.Json;
using System;
using System.IO;
using static PakReader.AssetReader;
namespace PakReader
{
public struct FText
{
[JsonIgnore]
public uint flags;
[JsonIgnore]
public byte history_type;
public string @namespace;
public string key;
public string source_string;
internal FText(BinaryReader reader)
{
flags = reader.ReadUInt32();
history_type = reader.ReadByte();
if (history_type == 255)
{
@namespace = "";
key = "";
source_string = "";
}
else if (history_type == 0)
{
@namespace = read_string(reader);
key = read_string(reader);
source_string = read_string(reader);
}
else
{
throw new NotImplementedException($"Could not read history type: {history_type}");
}
}
}
}

View File

@ -0,0 +1,28 @@
using Newtonsoft.Json;
using System.IO;
using static PakReader.AssetReader;
namespace PakReader
{
public struct FTexture2DMipMap
{
[JsonIgnore]
public FByteBulkData data;
public int size_x;
public int size_y;
public int size_z;
internal FTexture2DMipMap(BinaryReader reader, BinaryReader ubulk, long bulk_offset)
{
int cooked = reader.ReadInt32();
data = new FByteBulkData(reader, ubulk, bulk_offset);
size_x = reader.ReadInt32();
size_y = reader.ReadInt32();
size_z = reader.ReadInt32();
if (cooked != 1)
{
read_string(reader);
}
}
}
}

View File

@ -0,0 +1,35 @@
using System.IO;
using static PakReader.AssetReader;
namespace PakReader
{
public struct FTexturePlatformData
{
public int size_x;
public int size_y;
public int num_slices;
public string pixel_format;
public int first_mip;
public bool is_virtual;
public FTexture2DMipMap[] mips;
internal FTexturePlatformData(BinaryReader reader, BinaryReader ubulk, long bulk_offset)
{
size_x = reader.ReadInt32();
size_y = reader.ReadInt32();
num_slices = reader.ReadInt32();
pixel_format = read_string(reader);
first_mip = reader.ReadInt32();
mips = new FTexture2DMipMap[reader.ReadUInt32()];
for (int i = 0; i < mips.Length; i++)
{
mips[i] = new FTexture2DMipMap(reader, ubulk, bulk_offset);
}
is_virtual = reader.ReadInt32() == 1;
if (is_virtual)
{
throw new IOException("Texture is virtual, unsupported for now");
}
}
}
}

View File

@ -0,0 +1,12 @@
namespace PakReader
{
public struct FTrack
{
public FVector[] translation;
public FQuat[] rotation;
public FVector[] scale;
public float[] translation_times;
public float[] rotation_times;
public float[] scale_times;
}
}

View File

@ -0,0 +1,76 @@
using System;
using System.IO;
namespace PakReader
{
public struct FVector : IEquatable<FVector>
{
public float X;
public float Y;
public float Z;
internal FVector(BinaryReader reader)
{
X = reader.ReadSingle();
Y = reader.ReadSingle();
Z = reader.ReadSingle();
}
public static FVector operator -(FVector a, FVector b)
{
return new FVector
{
X = a.X - b.X,
Y = a.Y - b.Y,
Z = a.Z - b.Z
};
}
public static FVector operator +(FVector a, FVector b)
{
return new FVector
{
X = a.X + b.X,
Y = a.Y + b.Y,
Z = a.Z + b.Z
};
}
public bool Equals(FVector other) => other.X == X && other.Y == Y && other.Z == Z;
//public static bool operator ==(FVector a, FVector b) => a.Equals(b);
//public static bool operator !=(FVector a, FVector b) => !a.Equals(b);
public static implicit operator CVec3(FVector me) => new CVec3
{
v = new float[] { me.X, me.Y, me.Z }
};
public static implicit operator FVector(CVec3 me) => new FVector
{
X = me.v[0],
Y = me.v[1],
Z = me.v[2]
};
public static implicit operator CVec4(FVector me) => new CVec4
{
v = new float[] { me.X, me.Y, me.Z, 0 }
};
public static implicit operator FVector(FPackedNormal V) => new FVector
{
X = ((V.Data & 0xFF) / 127.5f) - 1,
Y = ((V.Data >> 8 & 0xFF) / 127.5f) - 1,
Z = ((V.Data >> 16 & 0xFF) / 127.5f) - 1
};
public void Write(BinaryWriter writer)
{
writer.Write(X);
writer.Write(Y);
writer.Write(Z);
}
}
}

View File

@ -0,0 +1,16 @@
using System.IO;
namespace PakReader
{
public struct FVector2D
{
public float x;
public float y;
internal FVector2D(BinaryReader reader)
{
x = reader.ReadSingle();
y = reader.ReadSingle();
}
}
}

View File

@ -0,0 +1,102 @@
using System.IO;
namespace PakReader
{
public struct UScriptStruct
{
public string struct_name;
public object struct_type;
internal UScriptStruct(BinaryReader reader, FNameEntrySerialized[] name_map, FObjectImport[] import_map, string struct_name)
{
this.struct_name = struct_name;
switch (struct_name)
{
case "Vector2D":
struct_type = new FVector2D(reader);
break;
case "LinearColor":
struct_type = new FLinearColor(reader);
break;
case "Color":
struct_type = new FColor(reader);
break;
case "GameplayTagContainer":
struct_type = new FGameplayTagContainer(reader, name_map);
break;
case "IntPoint":
struct_type = new FIntPoint(reader);
break;
case "Guid":
struct_type = new FGuid(reader);
break;
case "Quat":
struct_type = new FQuat(reader);
break;
case "Vector":
struct_type = new FVector(reader);
break;
case "Rotator":
struct_type = new FRotator(reader);
break;
case "SoftObjectPath":
struct_type = new FSoftObjectPath(reader, name_map);
break;
case "LevelSequenceObjectReferenceMap":
struct_type = new FLevelSequenceObjectReferenceMap(reader);
break;
case "FrameNumber":
struct_type = reader.ReadSingle();
break;/*
case "SectionEvaluationDataTree":
struct_type = new FSectionEvaluationDataTree(reader, name_map, import_map);
break;
case "MovieSceneTrackIdentifier":
struct_type = reader.ReadSingle();
break;
case "MovieSceneSegment":
struct_type = new FMovieSceneSegment(reader, name_map, import_map);
break;
case "MovieSceneEvalTemplatePtr":
struct_type = new InlineUStruct(reader, name_map, import_map);
break;
case "MovieSceneTrackImplementationPtr":
struct_type = new InlineUStruct(reader, name_map, import_map);
break;
case "MovieSceneSequenceInstanceDataPtr":
struct_type = new InlineUStruct(reader, name_map, import_map);
break;
case "MovieSceneFrameRange":
struct_type = new FMovieSceneFrameRange(reader, name_map, import_map);
break;
case "MovieSceneSegmentIdentifier":
struct_type = reader.ReadSingle();
break;
case "MovieSceneSequenceID":
struct_type = reader.ReadSingle();
break;
case "MovieSceneEvaluationKey":
struct_type = new FMovieSceneEvaluationKey(reader, name_map, import_map);
break;*/
case "SmartName":
struct_type = new FSmartName(reader, name_map);
break;
case "RichCurveKey":
struct_type = new FRichCurveKey(reader);
break;
case "SimpleCurveKey":
struct_type = new FSimpleCurveKey(reader);
break;
case "DateTime":
struct_type = new FDateTime(reader);
break;
case "Timespan":
struct_type = new FDateTime(reader);
break;
default:
struct_type = new FStructFallback(reader, name_map, import_map);
break;
}
}
}
}

View File

@ -0,0 +1,96 @@
using System;
using System.IO;
using System.Linq;
namespace PakReader
{
public sealed class USkeletalMesh : ExportObject
{
public UObject BaseObject;
public FBoxSphereBounds Bounds;
public FSkeletalMaterial[] Materials;
public FReferenceSkeleton RefSkeleton;
public FStaticLODModel[] LODModels;
public FSkeletalMeshLODInfo[] LODInfo;
public string[] MaterialAssets;
internal USkeletalMesh(BinaryReader reader, FNameEntrySerialized[] name_map, FObjectImport[] import_map)
{
BaseObject = new UObject(reader, name_map, import_map, "SkeletalMesh", true);
bool has_vertex_colors = false;
foreach (var prop in BaseObject.properties)
{
if (prop.name == "bHasVertexColors" && prop.tag == FPropertyTagType.BoolProperty)
{
has_vertex_colors = (bool)prop.tag_data;
}
else if (prop.name == "LODInfo")
{
var data = ((UScriptArray)prop.tag_data).data;
LODInfo = new FSkeletalMeshLODInfo[data.Length];
for (int i = 0; i < data.Length; i++)
{
var info = (UScriptStruct)data[i];
if (info.struct_name != "SkeletalMeshLODInfo")
{
throw new FileLoadException("Invalid lod info type");
}
var props = ((FStructFallback)info.struct_type).properties;
var newInfo = new FSkeletalMeshLODInfo();
foreach (var lodProp in props)
{
switch (lodProp.name)
{
case "DisplayFactor":
newInfo.DisplayFactor = (float)lodProp.tag_data;
break;
case "LODHysteresis":
newInfo.LODHysteresis = (float)lodProp.tag_data;
break;
case "LODMaterialMap":
newInfo.LODMaterialMap = ((UScriptArray)lodProp.tag_data).data.Cast<int>().ToArray();
break;
case "bEnableShadowCasting":
newInfo.bEnableShadowCasting = ((UScriptArray)lodProp.tag_data).data.Cast<bool>().ToArray();
break;
}
}
LODInfo[i] = newInfo;
}
}
}
var flags = new FStripDataFlags(reader);
Bounds = new FBoxSphereBounds(reader);
Materials = reader.ReadTArray(() => new FSkeletalMaterial(reader, name_map, import_map));
RefSkeleton = new FReferenceSkeleton(reader, name_map);
if (!flags.editor_data_stripped)
{
Console.WriteLine("Editor data still present!");
}
if (reader.ReadUInt32() == 0)
{
throw new FileLoadException("No cooked data");
}
LODModels = reader.ReadTArray(() => new FStaticLODModel(reader, name_map, has_vertex_colors));
uint serialize_guid = reader.ReadUInt32();
MaterialAssets = new string[Materials.Length];
for (int i = 0; i < Materials.Length; i++)
{
if (Materials[i].Material.import == null) continue;
for (int j = 0; j < import_map.Length; j++)
{
if (import_map[j].class_name != "MaterialInstanceConstant" && import_map[j].object_name.EndsWith(Materials[i].Material.import))
{
MaterialAssets[i] = import_map[j].object_name;
break;
}
}
}
}
}
}

View File

@ -0,0 +1,24 @@
using System.IO;
using static PakReader.AssetReader;
namespace PakReader
{
public sealed class USkeleton : ExportObject
{
public UObject super_object;
public FReferenceSkeleton reference_skeleton;
public (string, FReferencePose)[] anim_retarget_sources;
internal USkeleton(BinaryReader reader, FNameEntrySerialized[] name_map, FObjectImport[] import_map)
{
super_object = new UObject(reader, name_map, import_map, "Skeleton", true);
reference_skeleton = new FReferenceSkeleton(reader, name_map);
anim_retarget_sources = new (string, FReferencePose)[reader.ReadUInt32()];
for (int i = 0; i < anim_retarget_sources.Length; i++)
{
anim_retarget_sources[i] = (read_fname(reader, name_map), new FReferencePose(reader, name_map));
}
}
}
}

View File

@ -0,0 +1,87 @@
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using static PakReader.AssetReader;
namespace PakReader
{
public sealed class USoundWave : ExportObject, IDisposable
{
[JsonIgnore]
public UObject base_object;
[JsonIgnore]
public bool bStreaming;
[JsonIgnore]
public bool bCooked;
[JsonIgnore]
public FByteBulkData rawData;
[JsonIgnore]
public FGuid compressedDataGUID;
[JsonIgnore]
public List<FSoundFormatData> compressedFormatData;
public string format;
[JsonIgnore]
public List<FStreamedAudioChunk> streamedAudioChunks;
[JsonIgnore]
public int sampleRate;
[JsonIgnore]
public int numChannels;
internal USoundWave(BinaryReader reader, FNameEntrySerialized[] name_map, FObjectImport[] import_map, int asset_file_size, long export_size, BinaryReader ubulk)
{
base_object = new UObject(reader, name_map, import_map, "SoundWave", true);
bCooked = reader.ReadInt32() == 1;
bStreaming = false;
FPropertyTag streamingProperty = base_object.properties.Where(x => x.name == "bStreaming").Select(x => x).FirstOrDefault();
if (streamingProperty.name != null)
{
if (streamingProperty.tag == FPropertyTagType.BoolProperty)
{
bStreaming = (bool)streamingProperty.tag_data;
}
}
if (!bStreaming)
{
if (bCooked)
{
compressedFormatData = new List<FSoundFormatData>();
int elemCount = reader.ReadInt32();
for (int i = 0; i < elemCount; i++)
{
compressedFormatData.Add(new FSoundFormatData(reader, name_map, asset_file_size, export_size, ubulk));
format = compressedFormatData[i].name;
}
compressedDataGUID = new FGuid(reader);
}
else
{
rawData = new FByteBulkData(reader, ubulk, export_size + asset_file_size);
compressedDataGUID = new FGuid(reader);
}
}
else
{
compressedDataGUID = new FGuid(reader);
int numChunks = reader.ReadInt32();
format = read_fname(reader, name_map);
streamedAudioChunks = new List<FStreamedAudioChunk>();
for (int i = 0; i < numChunks; i++)
{
streamedAudioChunks.Add(new FStreamedAudioChunk(reader, asset_file_size, export_size, ubulk));
}
}
}
public void Dispose()
{
base_object = null;
rawData = new FByteBulkData();
compressedDataGUID = new FGuid();
compressedFormatData = null;
streamedAudioChunks = null;
}
}
}

View File

@ -294,43 +294,6 @@ namespace PakReader
}
}
public struct FGuid
{
public uint A, B, C, D;
public FGuid(BinaryReader reader)
{
A = reader.ReadUInt32();
B = reader.ReadUInt32();
C = reader.ReadUInt32();
D = reader.ReadUInt32();
}
public override bool Equals(object obj) => obj is FGuid ? this == (FGuid)obj : false;
public override int GetHashCode()
{
return (int)(((long)A + B + C + D) % uint.MaxValue - int.MaxValue);
}
public override string ToString()
{
return $"{A}-{B}-{C}-{D}";
}
public static bool operator ==(FGuid a, FGuid b) =>
a.A == b.A &&
a.B == b.B &&
a.C == b.C &&
a.D == b.D;
public static bool operator !=(FGuid a, FGuid b) =>
a.A != b.A ||
a.B != b.B ||
a.C != b.C ||
a.D != b.D;
}
internal struct FString
{
public string str;

View File

@ -202,7 +202,12 @@ namespace FModel.Methods.Utilities
{
string path = FProp.Default.FOutput_Path + "\\Sounds\\" + FWindow.FCurrentAsset + ".ogg";
File.WriteAllBytes(path, s);
FoldersUtility.OpenWithDefaultProgram(path);
//open sound
if (FProp.Default.FOpenSounds)
{
FoldersUtility.OpenWithDefaultProgram(path);
}
}
GC.Collect();

View File

@ -1,10 +1,10 @@
//------------------------------------------------------------------------------
// <auto-generated>
// Este código fue generado por una herramienta.
// Versión de runtime:4.0.30319.42000
// Ce code a été généré par un outil.
// Version du runtime :4.0.30319.42000
//
// Los cambios en este archivo podrían causar un comportamiento incorrecto y se perderán si
// se vuelve a generar el código.
// Les modifications apportées à ce fichier peuvent provoquer un comportement incorrect et seront perdues si
// le code est régénéré.
// </auto-generated>
//------------------------------------------------------------------------------
@ -12,7 +12,7 @@ namespace FModel.Properties {
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "15.9.0.0")]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "16.2.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
@ -310,5 +310,17 @@ namespace FModel.Properties {
this["ReloadAES"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("True")]
public bool FOpenSounds {
get {
return ((bool)(this["FOpenSounds"]));
}
set {
this["FOpenSounds"] = value;
}
}
}
}

View File

@ -74,5 +74,8 @@
<Setting Name="ReloadAES" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">True</Value>
</Setting>
<Setting Name="FOpenSounds" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">True</Value>
</Setting>
</Settings>
</SettingsFile>