commit e46416e546c1bb0272f4d5de518945a3ee2dec5b Author: Raymonf Date: Wed Sep 28 18:37:28 2022 -0400 Initial commit (galliumhook and WTT) diff --git a/README.md b/README.md new file mode 100644 index 0000000..837573d --- /dev/null +++ b/README.md @@ -0,0 +1,6 @@ +# whack + +A collection of tools and other hacky things I've made for myself. User beware! + +* galliumhook - injects `mercuryhook.dll` (whatever that may be) forces created windows to be 1080x1920 regardless of screen resolution +* Translation/WTT - translation tool that exports message tables to and imports from toml files [(readme)](WTT/README.md) diff --git a/Translation/.gitignore b/Translation/.gitignore new file mode 100644 index 0000000..8dd4607 --- /dev/null +++ b/Translation/.gitignore @@ -0,0 +1,398 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore + +# User-specific files +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Mono auto generated files +mono_crash.* + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Ww][Ii][Nn]32/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ +[Ll]ogs/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUnit +*.VisualState.xml +TestResult.xml +nunit-*.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# ASP.NET Scaffolding +ScaffoldingReadMe.txt + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.log +*.tlog +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Coverlet is a free, cross platform Code Coverage Tool +coverage*.json +coverage*.xml +coverage*.info + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# NuGet Symbol Packages +*.snupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx +*.appxbundle +*.appxupload + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!?*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser +*- [Bb]ackup.rdl +*- [Bb]ackup ([0-9]).rdl +*- [Bb]ackup ([0-9][0-9]).rdl + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio 6 auto-generated project file (contains which files were open etc.) +*.vbp + +# Visual Studio 6 workspace and project file (working project files containing files to include in project) +*.dsw +*.dsp + +# Visual Studio 6 technical files +*.ncb +*.aps + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# CodeRush personal settings +.cr/personal + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ + +# Visual Studio History (VSHistory) files +.vshistory/ + +# BeatPulse healthcheck temp database +healthchecksdb + +# Backup folder for Package Reference Convert tool in Visual Studio 2017 +MigrationBackup/ + +# Ionide (cross platform F# VS Code tools) working folder +.ionide/ + +# Fody - auto-generated XML schema +FodyWeavers.xsd + +# VS Code files for those working on multiple tools +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +*.code-workspace + +# Local History for Visual Studio Code +.history/ + +# Windows Installer files from build outputs +*.cab +*.msi +*.msix +*.msm +*.msp + +# JetBrains Rider +*.sln.iml \ No newline at end of file diff --git a/Translation/.idea/.idea.UAssetAPI/.idea/.gitignore b/Translation/.idea/.idea.UAssetAPI/.idea/.gitignore new file mode 100644 index 0000000..e3eb787 --- /dev/null +++ b/Translation/.idea/.idea.UAssetAPI/.idea/.gitignore @@ -0,0 +1,13 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Rider ignored files +/modules.xml +/contentModel.xml +/.idea.UAssetAPI.iml +/projectSettingsUpdater.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/Translation/.idea/.idea.UAssetAPI/.idea/encodings.xml b/Translation/.idea/.idea.UAssetAPI/.idea/encodings.xml new file mode 100644 index 0000000..df87cf9 --- /dev/null +++ b/Translation/.idea/.idea.UAssetAPI/.idea/encodings.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Translation/.idea/.idea.UAssetAPI/.idea/indexLayout.xml b/Translation/.idea/.idea.UAssetAPI/.idea/indexLayout.xml new file mode 100644 index 0000000..7b08163 --- /dev/null +++ b/Translation/.idea/.idea.UAssetAPI/.idea/indexLayout.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/Translation/.idea/.idea.UAssetAPI/.idea/vcs.xml b/Translation/.idea/.idea.UAssetAPI/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/Translation/.idea/.idea.UAssetAPI/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/Translation/LICENSE b/Translation/LICENSE new file mode 100644 index 0000000..57dc7d8 --- /dev/null +++ b/Translation/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2022 Atenfyr (UAssetAPI), Raymonf (WTT) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Translation/README.md b/Translation/README.md new file mode 100644 index 0000000..17db62d --- /dev/null +++ b/Translation/README.md @@ -0,0 +1,25 @@ +# WTT + +Based on [UAssetAPI](https://github.com/atenfyr/UAssetAPI). + +It replaces existing strings, so you can't add new ones. Tested on version 3.7.10. + +**Beware:** There is no error handling since this tool was originally meant for my personal use. + +### Compilation + +Compile like a normal .NET 6 application. WTT.sln has everything you will need if you use Visual Studio. + +### Usage + +When it asks, put in the path to your `Message` directory. Usually, this would be `C:\whatever\WindowsNoEditor\Mercury\Content\Message`. + +Then, choose a mode: + +* **bulk_export** - bulk export all the `uasset` files in the path given as toml files in the same directory +* **bulk_import** - bulk import all the `toml` files + * directory of TOML files: where your TOML files are + * uasset directory: where your uasset files are (useful as a way to back up the original uasset files) + * output uasset directory: where your new uasset files will be put +* **e** - export single toml file from uasset +* **i** - import single uasset file from toml diff --git a/Translation/UAssetAPI/AC7Decrypt.cs b/Translation/UAssetAPI/AC7Decrypt.cs new file mode 100644 index 0000000..cb81831 --- /dev/null +++ b/Translation/UAssetAPI/AC7Decrypt.cs @@ -0,0 +1,201 @@ +using System; +using System.Diagnostics; +using System.IO; + +namespace UAssetAPI +{ + public class AC7XorKey + { + public int NameKey; + public int Offset; + public int pk1; + public int pk2; + + public void SkipCount(int count) + { + int num = count % 217; + pk1 += num; + if (pk1 >= 217) + { + pk1 -= 217; + } + int num2 = count % 1024; + pk2 += num2; + if (pk2 >= 1024) + { + pk2 -= 1024; + } + } + + public AC7XorKey(int nameKey, int offset) + { + NameKey = nameKey; + Offset = offset; + } + } + + public class AC7Decrypt + { + private static byte[] AC7FullKey = new byte[0]; + + public AC7Decrypt() + { + if (AC7FullKey.Length == 0) AC7FullKey = Properties.Resources.AC7Key; + } + + /// + /// Decrypts an Ace Combat 7 encrypted asset on disk. + /// + /// The path to an encrypted asset on disk. + /// The path that the decrypted asset should be saved to. + public void Decrypt(string input, string output) + { + AC7XorKey xorKey = GetXorKey(Path.GetFileNameWithoutExtension(input)); + byte[] doneData = DecryptUAssetBytes(File.ReadAllBytes(input), xorKey); + File.WriteAllBytes(output, doneData); + try + { + byte[] doneData2 = DecryptUexpBytes(File.ReadAllBytes(Path.ChangeExtension(input, "uexp")), xorKey); + File.WriteAllBytes(Path.ChangeExtension(output, "uexp"), doneData2); + } + catch { } + } + + /// + /// Encrypts an Ace Combat 7 encrypted asset on disk. + /// + /// The path to a decrypted asset on disk. + /// The path that the encrypted asset should be saved to. + public void Encrypt(string input, string output) + { + AC7XorKey xorKey = GetXorKey(Path.GetFileNameWithoutExtension(output)); + byte[] doneData = EncryptUAssetBytes(File.ReadAllBytes(input), xorKey); + File.WriteAllBytes(output, doneData); + try + { + byte[] doneData2 = EncryptUexpBytes(File.ReadAllBytes(Path.ChangeExtension(input, "uexp")), xorKey); + File.WriteAllBytes(Path.ChangeExtension(output, "uexp"), doneData2); + } + catch { } + } + + public byte[] DecryptUAssetBytes(byte[] uasset, AC7XorKey xorkey) + { + if (xorkey == null) throw new NullReferenceException("Null key provided"); + byte[] array = new byte[uasset.Length]; + BitConverter.GetBytes(UAsset.UASSET_MAGIC).CopyTo(array, 0); + for (int i = 4; i < array.Length; i++) + { + array[i] = GetXorByte(uasset[i], ref xorkey); + } + return array; + } + + public byte[] EncryptUAssetBytes(byte[] uasset, AC7XorKey xorkey) + { + if (xorkey == null) throw new NullReferenceException("Null key provided"); + byte[] array = new byte[uasset.Length]; + BitConverter.GetBytes(UAsset.ACE7_MAGIC).CopyTo(array, 0); + for (int i = 4; i < array.Length; i++) + { + array[i] = GetXorByte(uasset[i], ref xorkey); + } + return array; + } + + public byte[] DecryptUexpBytes(byte[] uexp, AC7XorKey xorkey) + { + if (xorkey == null) throw new NullReferenceException("Null key provided"); + byte[] array = new byte[uexp.Length]; + for (int i = 0; i < array.Length; i++) + { + array[i] = GetXorByte(uexp[i], ref xorkey); + } + BitConverter.GetBytes(UAsset.UASSET_MAGIC).CopyTo(array, array.Length - 4); + return array; + } + + public byte[] EncryptUexpBytes(byte[] uexp, AC7XorKey xorkey) + { + if (xorkey == null) throw new NullReferenceException("Null key provided"); + byte[] array = new byte[uexp.Length]; + for (int i = 0; i < uexp.Length; i++) + { + array[i] = GetXorByte(uexp[i], ref xorkey); + } + return array; + } + + /// + /// Generates an encryption key for a particular asset on disk. + /// + /// The name of the asset being encrypted on disk without the extension. + /// An encryption key for the asset. + public static AC7XorKey GetXorKey(string fname) + { + AC7XorKey key = new AC7XorKey(CalcNameKey(fname), 4); + CalcPKeyFromNKey(key.NameKey, key.Offset, out key.pk1, out key.pk2); + return key; + } + + private static int CalcNameKey(string fname) + { + fname = fname.ToUpper(); + int num = 0; + for (int i = 0; i < fname.Length; i++) + { + int num2 = (byte)fname[i]; + num ^= num2; + num2 = num * 8; + num2 ^= num; + int num3 = num + num; + num2 = ~num2; + num2 = (num2 >> 7) & 1; + num = num2 | num3; + } + return num; + } + + private static void CalcPKeyFromNKey(int nkey, int dataoffset, out int pk1, out int pk2) + { + long num = (uint)((long)nkey * 7L); + System.Numerics.BigInteger bigInteger = new System.Numerics.BigInteger(5440514381186227205L); + num += dataoffset; + System.Numerics.BigInteger bigInteger2 = bigInteger * num; + long num2 = (long)(bigInteger2 >> 70); + long num3 = num2 >> 63; + num2 += num3; + num3 = num2 * 217; + num -= num3; + pk1 = (int)(num & 0xFFFFFFFFu); + long num4 = (uint)((long)nkey * 11L); + num4 += dataoffset; + num2 = 0L; + num2 &= 0x3FF; + num4 += num2; + num4 &= 0x3FF; + long num5 = num4 - num2; + pk2 = (int)(num5 & 0xFFFFFFFFu); + } + + private static byte GetXorByte(byte tagb, ref AC7XorKey xorkey) + { + if (xorkey == null) + { + return tagb; + } + tagb = (byte)((uint)(tagb ^ AC7FullKey[xorkey.pk1 * 1024 + xorkey.pk2]) ^ 0x77u); + xorkey.pk1++; + xorkey.pk2++; + if (xorkey.pk1 >= 217) + { + xorkey.pk1 = 0; + } + if (xorkey.pk2 >= 1024) + { + xorkey.pk2 = 0; + } + return tagb; + } + } +} diff --git a/Translation/UAssetAPI/AssetBinaryReader.cs b/Translation/UAssetAPI/AssetBinaryReader.cs new file mode 100644 index 0000000..9d2060d --- /dev/null +++ b/Translation/UAssetAPI/AssetBinaryReader.cs @@ -0,0 +1,207 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; +using UAssetAPI.Kismet.Bytecode; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI +{ + public class AssetBinaryReader : BinaryReader + { + public UAsset Asset; + + public AssetBinaryReader(Stream stream, UAsset asset) : base(stream) + { + Asset = asset; + } + + private byte[] ReverseIfBigEndian(byte[] data) + { + if (!BitConverter.IsLittleEndian) Array.Reverse(data); + return data; + } + + public override short ReadInt16() + { + return BitConverter.ToInt16(ReverseIfBigEndian(base.ReadBytes(2)), 0); + } + + public override ushort ReadUInt16() + { + return BitConverter.ToUInt16(ReverseIfBigEndian(base.ReadBytes(2)), 0); + } + + public override int ReadInt32() + { + return BitConverter.ToInt32(ReverseIfBigEndian(base.ReadBytes(4)), 0); + } + + public override uint ReadUInt32() + { + return BitConverter.ToUInt32(ReverseIfBigEndian(base.ReadBytes(4)), 0); + } + + public override long ReadInt64() + { + return BitConverter.ToInt64(ReverseIfBigEndian(base.ReadBytes(8)), 0); + } + + public override ulong ReadUInt64() + { + return BitConverter.ToUInt64(ReverseIfBigEndian(base.ReadBytes(8)), 0); + } + + public override float ReadSingle() + { + return BitConverter.ToSingle(ReverseIfBigEndian(base.ReadBytes(4)), 0); + } + + public override double ReadDouble() + { + return BitConverter.ToDouble(ReverseIfBigEndian(base.ReadBytes(8)), 0); + } + + public override string ReadString() + { + return ReadFString()?.Value; + } + + public virtual Guid? ReadPropertyGuid() + { + if (Asset.EngineVersion >= UE4Version.VER_UE4_PROPERTY_GUID_IN_PROPERTY_TAG) + { + bool hasPropertyGuid = ReadBoolean(); + if (hasPropertyGuid) return new Guid(ReadBytes(16)); + } + return null; + } + + public virtual FString ReadFString() + { + int length = this.ReadInt32(); + switch (length) + { + case 0: + return null; + default: + if (length < 0) + { + byte[] data = this.ReadBytes(-length * 2); + return new FString(Encoding.Unicode.GetString(data, 0, data.Length - 2), Encoding.Unicode); + } + else + { + byte[] data = this.ReadBytes(length); + return new FString(Encoding.ASCII.GetString(data, 0, data.Length - 1), Encoding.ASCII); + } + } + } + + public virtual FString ReadNameMapString(out uint hashes) + { + FString str = this.ReadFString(); + hashes = 0; + + if (Asset.EngineVersion >= UE4Version.VER_UE4_NAME_HASHES_SERIALIZED && !string.IsNullOrEmpty(str.Value)) + { + hashes = this.ReadUInt32(); + } + return str; + } + + public virtual FName ReadFName() + { + int nameMapPointer = this.ReadInt32(); + int number = this.ReadInt32(); + return new FName(Asset, nameMapPointer, number); + } + + public string XFERSTRING() + { + List readData = new List(); + while (true) + { + byte newVal = this.ReadByte(); + if (newVal == 0) break; + readData.Add(newVal); + } + return Encoding.ASCII.GetString(readData.ToArray()); + } + + public string XFERUNICODESTRING() + { + List readData = new List(); + while (true) + { + byte newVal1 = this.ReadByte(); + byte newVal2 = this.ReadByte(); + if (newVal1 == 0 && newVal2 == 0) break; + readData.Add(newVal1); + readData.Add(newVal2); + } + return Encoding.Unicode.GetString(readData.ToArray()); + } + + public void XFERTEXT() + { + + } + + public FName XFERNAME() + { + return this.ReadFName(); + } + + public FName XFER_FUNC_NAME() + { + return this.XFERNAME(); + } + + public FPackageIndex XFERPTR() + { + return new FPackageIndex(this.ReadInt32()); + } + + public FPackageIndex XFER_FUNC_POINTER() + { + return this.XFERPTR(); + } + + public KismetPropertyPointer XFER_PROP_POINTER() + { + if (Asset.EngineVersion >= KismetPropertyPointer.XFER_PROP_POINTER_SWITCH_TO_SERIALIZING_AS_FIELD_PATH_VERSION) + { + int numEntries = this.ReadInt32(); + FName[] allNames = new FName[numEntries]; + for (int i = 0; i < numEntries; i++) + { + allNames[i] = this.ReadFName(); + } + FPackageIndex owner = this.XFER_OBJECT_POINTER(); + return new KismetPropertyPointer(new FFieldPath(allNames, owner)); + } + else + { + return new KismetPropertyPointer(this.XFERPTR()); + } + } + + public FPackageIndex XFER_OBJECT_POINTER() + { + return this.XFERPTR(); + } + + public KismetExpression[] ReadExpressionArray(EExprToken endToken) + { + List newData = new List(); + KismetExpression currExpression = null; + while (currExpression == null || currExpression.Token != endToken) + { + if (currExpression != null) newData.Add(currExpression); + currExpression = ExpressionSerializer.ReadExpression(this); + } + return newData.ToArray(); + } + } +} diff --git a/Translation/UAssetAPI/AssetBinaryWriter.cs b/Translation/UAssetAPI/AssetBinaryWriter.cs new file mode 100644 index 0000000..e2cec38 --- /dev/null +++ b/Translation/UAssetAPI/AssetBinaryWriter.cs @@ -0,0 +1,176 @@ +using System; +using System.IO; +using System.Text; +using UAssetAPI.Kismet.Bytecode; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI +{ + public class AssetBinaryWriter : BinaryWriter + { + public UAsset Asset; + + public AssetBinaryWriter(UAsset asset) : base() + { + Asset = asset; + } + + public AssetBinaryWriter(Stream stream, UAsset asset) : base(stream) + { + Asset = asset; + } + + public AssetBinaryWriter(Stream stream, Encoding encoding, UAsset asset) : base(stream, encoding) + { + Asset = asset; + } + + public AssetBinaryWriter(Stream stream, Encoding encoding, bool leaveOpen, UAsset asset) : base(stream, encoding, leaveOpen) + { + Asset = asset; + } + + private byte[] ReverseIfBigEndian(byte[] data) + { + if (!BitConverter.IsLittleEndian) Array.Reverse(data); + return data; + } + + public override void Write(short value) + { + this.Write(ReverseIfBigEndian(BitConverter.GetBytes(value))); + } + + public override void Write(ushort value) + { + this.Write(ReverseIfBigEndian(BitConverter.GetBytes(value))); + } + + public override void Write(int value) + { + this.Write(ReverseIfBigEndian(BitConverter.GetBytes(value))); + } + + public override void Write(uint value) + { + this.Write(ReverseIfBigEndian(BitConverter.GetBytes(value))); + } + + public override void Write(long value) + { + this.Write(ReverseIfBigEndian(BitConverter.GetBytes(value))); + } + + public override void Write(ulong value) + { + this.Write(ReverseIfBigEndian(BitConverter.GetBytes(value))); + } + + public override void Write(float value) + { + this.Write(ReverseIfBigEndian(BitConverter.GetBytes(value))); + } + + public override void Write(double value) + { + this.Write(ReverseIfBigEndian(BitConverter.GetBytes(value))); + } + + public override void Write(string value) + { + Write(new FString(value)); + } + + public virtual int Write(FString value) + { + switch (value?.Value) + { + case null: + this.Write((int)0); + return sizeof(int); + default: + string nullTerminatedStr = value.Value + "\0"; + this.Write(value.Encoding is UnicodeEncoding ? -nullTerminatedStr.Length : nullTerminatedStr.Length); + byte[] actualStrData = value.Encoding.GetBytes(nullTerminatedStr); + this.Write(actualStrData); + return actualStrData.Length + 4; + } + } + + public virtual void Write(FName name) + { + this.Write(name.Index); + this.Write(name.Number); + } + + public virtual void WritePropertyGuid(Guid? guid) + { + if (Asset.EngineVersion >= UE4Version.VER_UE4_PROPERTY_GUID_IN_PROPERTY_TAG) + { + Write(guid != null); + if (guid != null) Write(((Guid)guid).ToByteArray()); + } + } + + public int XFERSTRING(string val) + { + long startMetric = this.BaseStream.Position; + this.Write(Encoding.ASCII.GetBytes(val + "\0")); + return (int)(this.BaseStream.Position - startMetric); + } + + public int XFERUNICODESTRING(string val) + { + long startMetric = this.BaseStream.Position; + this.Write(Encoding.Unicode.GetBytes(val + "\0")); + return (int)(this.BaseStream.Position - startMetric); + } + + public int XFERNAME(FName val) + { + this.Write(val); + return 12; // FScriptName's iCode offset is 12 bytes, not 8 + } + + public int XFER_FUNC_NAME(FName val) + { + return this.XFERNAME(val); + } + + private static readonly int PointerSize = sizeof(ulong); + + public int XFERPTR(FPackageIndex val) + { + this.Write(val.Index); + return PointerSize; // For the iCode offset, we return the size of a pointer in memory rather than the size of an FPackageIndex on disk + } + + public int XFER_FUNC_POINTER(FPackageIndex val) + { + return this.XFERPTR(val); + } + + public int XFER_PROP_POINTER(KismetPropertyPointer val) + { + if (Asset.EngineVersion >= KismetPropertyPointer.XFER_PROP_POINTER_SWITCH_TO_SERIALIZING_AS_FIELD_PATH_VERSION) + { + this.Write(val.New.Path.Length); + for (int i = 0; i < val.New.Path.Length; i++) + { + this.XFERNAME(val.New.Path[i]); + } + this.XFER_OBJECT_POINTER(val.New.ResolvedOwner); + } + else + { + this.XFERPTR(val.Old); + } + return PointerSize; + } + + public int XFER_OBJECT_POINTER(FPackageIndex val) + { + return this.XFERPTR(val); + } + } +} diff --git a/Translation/UAssetAPI/CRCGenerator.cs b/Translation/UAssetAPI/CRCGenerator.cs new file mode 100644 index 0000000..120ba7d --- /dev/null +++ b/Translation/UAssetAPI/CRCGenerator.cs @@ -0,0 +1,233 @@ +using System; +using System.Diagnostics; +using System.Text; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI +{ + public static class CRCGenerator + { + public static uint GenerateHash(FString text) + { + return GenerateHash(text?.Value, text?.Encoding); + } + + public static uint GenerateHash(string text) + { + return GenerateHash(text, Encoding.ASCII); + } + + public static uint GenerateHash(string text, Encoding encoding) + { + uint algor1 = Strihash_DEPRECATED(text, encoding); + uint algor2 = StrCrc32(text); + return (algor1 & 0xFFFF) | ((algor2 & 0xFFFF) << 16); + } + + private static char ToUpper(char input) + { + return (char)((uint)input - ((((uint)input - 'a' < 26u) ? 1 : 0) << 5)); + } + + private static uint Strihash_DEPRECATED(string text, Encoding encoding) + { + uint hash = 0; + for (int i = 0; i < text.Length; i++) + { + char B = ToUpper(text[i]); + byte[] rawDataForCharacter = encoding.GetBytes(new char[1] { B }); + foreach (byte rawByte in rawDataForCharacter) + { + hash = ((hash >> 8) & 0x00FFFFFF) ^ CRCTable_DEPRECATED[(hash ^ rawByte) & 0x000000FF]; + } + } + return hash; + } + + // Accurate as-is for both WIDECHAR and ANSICHAR + private static uint StrCrc32(string text, uint CRC = 0) + { + CRC = ~CRC; + for (int i = 0; i < text.Length; i++) + { + char Ch = text[i]; + CRC = (CRC >> 8) ^ CRCTablesSB8[0, (CRC ^ Ch) & 0xFF]; + Ch >>= 8; + CRC = (CRC >> 8) ^ CRCTablesSB8[0, (CRC ^ Ch) & 0xFF]; + Ch >>= 8; + CRC = (CRC >> 8) ^ CRCTablesSB8[0, (CRC ^ Ch) & 0xFF]; + Ch >>= 8; + CRC = (CRC >> 8) ^ CRCTablesSB8[0, (CRC ^ Ch) & 0xFF]; + } + return ~CRC; + } + + private static readonly uint[] CRCTable_DEPRECATED = new uint[256] + { + 0x00000000, 0x04C11DB7, 0x09823B6E, 0x0D4326D9, 0x130476DC, 0x17C56B6B, 0x1A864DB2, 0x1E475005, 0x2608EDB8, 0x22C9F00F, 0x2F8AD6D6, 0x2B4BCB61, 0x350C9B64, 0x31CD86D3, 0x3C8EA00A, 0x384FBDBD, + 0x4C11DB70, 0x48D0C6C7, 0x4593E01E, 0x4152FDA9, 0x5F15ADAC, 0x5BD4B01B, 0x569796C2, 0x52568B75, 0x6A1936C8, 0x6ED82B7F, 0x639B0DA6, 0x675A1011, 0x791D4014, 0x7DDC5DA3, 0x709F7B7A, 0x745E66CD, + 0x9823B6E0, 0x9CE2AB57, 0x91A18D8E, 0x95609039, 0x8B27C03C, 0x8FE6DD8B, 0x82A5FB52, 0x8664E6E5, 0xBE2B5B58, 0xBAEA46EF, 0xB7A96036, 0xB3687D81, 0xAD2F2D84, 0xA9EE3033, 0xA4AD16EA, 0xA06C0B5D, + 0xD4326D90, 0xD0F37027, 0xDDB056FE, 0xD9714B49, 0xC7361B4C, 0xC3F706FB, 0xCEB42022, 0xCA753D95, 0xF23A8028, 0xF6FB9D9F, 0xFBB8BB46, 0xFF79A6F1, 0xE13EF6F4, 0xE5FFEB43, 0xE8BCCD9A, 0xEC7DD02D, + 0x34867077, 0x30476DC0, 0x3D044B19, 0x39C556AE, 0x278206AB, 0x23431B1C, 0x2E003DC5, 0x2AC12072, 0x128E9DCF, 0x164F8078, 0x1B0CA6A1, 0x1FCDBB16, 0x018AEB13, 0x054BF6A4, 0x0808D07D, 0x0CC9CDCA, + 0x7897AB07, 0x7C56B6B0, 0x71159069, 0x75D48DDE, 0x6B93DDDB, 0x6F52C06C, 0x6211E6B5, 0x66D0FB02, 0x5E9F46BF, 0x5A5E5B08, 0x571D7DD1, 0x53DC6066, 0x4D9B3063, 0x495A2DD4, 0x44190B0D, 0x40D816BA, + 0xACA5C697, 0xA864DB20, 0xA527FDF9, 0xA1E6E04E, 0xBFA1B04B, 0xBB60ADFC, 0xB6238B25, 0xB2E29692, 0x8AAD2B2F, 0x8E6C3698, 0x832F1041, 0x87EE0DF6, 0x99A95DF3, 0x9D684044, 0x902B669D, 0x94EA7B2A, + 0xE0B41DE7, 0xE4750050, 0xE9362689, 0xEDF73B3E, 0xF3B06B3B, 0xF771768C, 0xFA325055, 0xFEF34DE2, 0xC6BCF05F, 0xC27DEDE8, 0xCF3ECB31, 0xCBFFD686, 0xD5B88683, 0xD1799B34, 0xDC3ABDED, 0xD8FBA05A, + 0x690CE0EE, 0x6DCDFD59, 0x608EDB80, 0x644FC637, 0x7A089632, 0x7EC98B85, 0x738AAD5C, 0x774BB0EB, 0x4F040D56, 0x4BC510E1, 0x46863638, 0x42472B8F, 0x5C007B8A, 0x58C1663D, 0x558240E4, 0x51435D53, + 0x251D3B9E, 0x21DC2629, 0x2C9F00F0, 0x285E1D47, 0x36194D42, 0x32D850F5, 0x3F9B762C, 0x3B5A6B9B, 0x0315D626, 0x07D4CB91, 0x0A97ED48, 0x0E56F0FF, 0x1011A0FA, 0x14D0BD4D, 0x19939B94, 0x1D528623, + 0xF12F560E, 0xF5EE4BB9, 0xF8AD6D60, 0xFC6C70D7, 0xE22B20D2, 0xE6EA3D65, 0xEBA91BBC, 0xEF68060B, 0xD727BBB6, 0xD3E6A601, 0xDEA580D8, 0xDA649D6F, 0xC423CD6A, 0xC0E2D0DD, 0xCDA1F604, 0xC960EBB3, + 0xBD3E8D7E, 0xB9FF90C9, 0xB4BCB610, 0xB07DABA7, 0xAE3AFBA2, 0xAAFBE615, 0xA7B8C0CC, 0xA379DD7B, 0x9B3660C6, 0x9FF77D71, 0x92B45BA8, 0x9675461F, 0x8832161A, 0x8CF30BAD, 0x81B02D74, 0x857130C3, + 0x5D8A9099, 0x594B8D2E, 0x5408ABF7, 0x50C9B640, 0x4E8EE645, 0x4A4FFBF2, 0x470CDD2B, 0x43CDC09C, 0x7B827D21, 0x7F436096, 0x7200464F, 0x76C15BF8, 0x68860BFD, 0x6C47164A, 0x61043093, 0x65C52D24, + 0x119B4BE9, 0x155A565E, 0x18197087, 0x1CD86D30, 0x029F3D35, 0x065E2082, 0x0B1D065B, 0x0FDC1BEC, 0x3793A651, 0x3352BBE6, 0x3E119D3F, 0x3AD08088, 0x2497D08D, 0x2056CD3A, 0x2D15EBE3, 0x29D4F654, + 0xC5A92679, 0xC1683BCE, 0xCC2B1D17, 0xC8EA00A0, 0xD6AD50A5, 0xD26C4D12, 0xDF2F6BCB, 0xDBEE767C, 0xE3A1CBC1, 0xE760D676, 0xEA23F0AF, 0xEEE2ED18, 0xF0A5BD1D, 0xF464A0AA, 0xF9278673, 0xFDE69BC4, + 0x89B8FD09, 0x8D79E0BE, 0x803AC667, 0x84FBDBD0, 0x9ABC8BD5, 0x9E7D9662, 0x933EB0BB, 0x97FFAD0C, 0xAFB010B1, 0xAB710D06, 0xA6322BDF, 0xA2F33668, 0xBCB4666D, 0xB8757BDA, 0xB5365D03, 0xB1F740B4 + }; + + private static readonly uint[,] CRCTablesSB8 = new uint[8, 256] + { + { + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, + 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, + 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, + 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, + 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, + 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, + 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, + 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, + 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, + 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, + 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, + 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, + 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, + 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, + 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d + }, + { + 0x00000000, 0x191b3141, 0x32366282, 0x2b2d53c3, 0x646cc504, 0x7d77f445, 0x565aa786, 0x4f4196c7, 0xc8d98a08, 0xd1c2bb49, 0xfaefe88a, 0xe3f4d9cb, 0xacb54f0c, 0xb5ae7e4d, 0x9e832d8e, 0x87981ccf, + 0x4ac21251, 0x53d92310, 0x78f470d3, 0x61ef4192, 0x2eaed755, 0x37b5e614, 0x1c98b5d7, 0x05838496, 0x821b9859, 0x9b00a918, 0xb02dfadb, 0xa936cb9a, 0xe6775d5d, 0xff6c6c1c, 0xd4413fdf, 0xcd5a0e9e, + 0x958424a2, 0x8c9f15e3, 0xa7b24620, 0xbea97761, 0xf1e8e1a6, 0xe8f3d0e7, 0xc3de8324, 0xdac5b265, 0x5d5daeaa, 0x44469feb, 0x6f6bcc28, 0x7670fd69, 0x39316bae, 0x202a5aef, 0x0b07092c, 0x121c386d, + 0xdf4636f3, 0xc65d07b2, 0xed705471, 0xf46b6530, 0xbb2af3f7, 0xa231c2b6, 0x891c9175, 0x9007a034, 0x179fbcfb, 0x0e848dba, 0x25a9de79, 0x3cb2ef38, 0x73f379ff, 0x6ae848be, 0x41c51b7d, 0x58de2a3c, + 0xf0794f05, 0xe9627e44, 0xc24f2d87, 0xdb541cc6, 0x94158a01, 0x8d0ebb40, 0xa623e883, 0xbf38d9c2, 0x38a0c50d, 0x21bbf44c, 0x0a96a78f, 0x138d96ce, 0x5ccc0009, 0x45d73148, 0x6efa628b, 0x77e153ca, + 0xbabb5d54, 0xa3a06c15, 0x888d3fd6, 0x91960e97, 0xded79850, 0xc7cca911, 0xece1fad2, 0xf5facb93, 0x7262d75c, 0x6b79e61d, 0x4054b5de, 0x594f849f, 0x160e1258, 0x0f152319, 0x243870da, 0x3d23419b, + 0x65fd6ba7, 0x7ce65ae6, 0x57cb0925, 0x4ed03864, 0x0191aea3, 0x188a9fe2, 0x33a7cc21, 0x2abcfd60, 0xad24e1af, 0xb43fd0ee, 0x9f12832d, 0x8609b26c, 0xc94824ab, 0xd05315ea, 0xfb7e4629, 0xe2657768, + 0x2f3f79f6, 0x362448b7, 0x1d091b74, 0x04122a35, 0x4b53bcf2, 0x52488db3, 0x7965de70, 0x607eef31, 0xe7e6f3fe, 0xfefdc2bf, 0xd5d0917c, 0xcccba03d, 0x838a36fa, 0x9a9107bb, 0xb1bc5478, 0xa8a76539, + 0x3b83984b, 0x2298a90a, 0x09b5fac9, 0x10aecb88, 0x5fef5d4f, 0x46f46c0e, 0x6dd93fcd, 0x74c20e8c, 0xf35a1243, 0xea412302, 0xc16c70c1, 0xd8774180, 0x9736d747, 0x8e2de606, 0xa500b5c5, 0xbc1b8484, + 0x71418a1a, 0x685abb5b, 0x4377e898, 0x5a6cd9d9, 0x152d4f1e, 0x0c367e5f, 0x271b2d9c, 0x3e001cdd, 0xb9980012, 0xa0833153, 0x8bae6290, 0x92b553d1, 0xddf4c516, 0xc4eff457, 0xefc2a794, 0xf6d996d5, + 0xae07bce9, 0xb71c8da8, 0x9c31de6b, 0x852aef2a, 0xca6b79ed, 0xd37048ac, 0xf85d1b6f, 0xe1462a2e, 0x66de36e1, 0x7fc507a0, 0x54e85463, 0x4df36522, 0x02b2f3e5, 0x1ba9c2a4, 0x30849167, 0x299fa026, + 0xe4c5aeb8, 0xfdde9ff9, 0xd6f3cc3a, 0xcfe8fd7b, 0x80a96bbc, 0x99b25afd, 0xb29f093e, 0xab84387f, 0x2c1c24b0, 0x350715f1, 0x1e2a4632, 0x07317773, 0x4870e1b4, 0x516bd0f5, 0x7a468336, 0x635db277, + 0xcbfad74e, 0xd2e1e60f, 0xf9ccb5cc, 0xe0d7848d, 0xaf96124a, 0xb68d230b, 0x9da070c8, 0x84bb4189, 0x03235d46, 0x1a386c07, 0x31153fc4, 0x280e0e85, 0x674f9842, 0x7e54a903, 0x5579fac0, 0x4c62cb81, + 0x8138c51f, 0x9823f45e, 0xb30ea79d, 0xaa1596dc, 0xe554001b, 0xfc4f315a, 0xd7626299, 0xce7953d8, 0x49e14f17, 0x50fa7e56, 0x7bd72d95, 0x62cc1cd4, 0x2d8d8a13, 0x3496bb52, 0x1fbbe891, 0x06a0d9d0, + 0x5e7ef3ec, 0x4765c2ad, 0x6c48916e, 0x7553a02f, 0x3a1236e8, 0x230907a9, 0x0824546a, 0x113f652b, 0x96a779e4, 0x8fbc48a5, 0xa4911b66, 0xbd8a2a27, 0xf2cbbce0, 0xebd08da1, 0xc0fdde62, 0xd9e6ef23, + 0x14bce1bd, 0x0da7d0fc, 0x268a833f, 0x3f91b27e, 0x70d024b9, 0x69cb15f8, 0x42e6463b, 0x5bfd777a, 0xdc656bb5, 0xc57e5af4, 0xee530937, 0xf7483876, 0xb809aeb1, 0xa1129ff0, 0x8a3fcc33, 0x9324fd72 + }, + { + 0x00000000, 0x01c26a37, 0x0384d46e, 0x0246be59, 0x0709a8dc, 0x06cbc2eb, 0x048d7cb2, 0x054f1685, 0x0e1351b8, 0x0fd13b8f, 0x0d9785d6, 0x0c55efe1, 0x091af964, 0x08d89353, 0x0a9e2d0a, 0x0b5c473d, + 0x1c26a370, 0x1de4c947, 0x1fa2771e, 0x1e601d29, 0x1b2f0bac, 0x1aed619b, 0x18abdfc2, 0x1969b5f5, 0x1235f2c8, 0x13f798ff, 0x11b126a6, 0x10734c91, 0x153c5a14, 0x14fe3023, 0x16b88e7a, 0x177ae44d, + 0x384d46e0, 0x398f2cd7, 0x3bc9928e, 0x3a0bf8b9, 0x3f44ee3c, 0x3e86840b, 0x3cc03a52, 0x3d025065, 0x365e1758, 0x379c7d6f, 0x35dac336, 0x3418a901, 0x3157bf84, 0x3095d5b3, 0x32d36bea, 0x331101dd, + 0x246be590, 0x25a98fa7, 0x27ef31fe, 0x262d5bc9, 0x23624d4c, 0x22a0277b, 0x20e69922, 0x2124f315, 0x2a78b428, 0x2bbade1f, 0x29fc6046, 0x283e0a71, 0x2d711cf4, 0x2cb376c3, 0x2ef5c89a, 0x2f37a2ad, + 0x709a8dc0, 0x7158e7f7, 0x731e59ae, 0x72dc3399, 0x7793251c, 0x76514f2b, 0x7417f172, 0x75d59b45, 0x7e89dc78, 0x7f4bb64f, 0x7d0d0816, 0x7ccf6221, 0x798074a4, 0x78421e93, 0x7a04a0ca, 0x7bc6cafd, + 0x6cbc2eb0, 0x6d7e4487, 0x6f38fade, 0x6efa90e9, 0x6bb5866c, 0x6a77ec5b, 0x68315202, 0x69f33835, 0x62af7f08, 0x636d153f, 0x612bab66, 0x60e9c151, 0x65a6d7d4, 0x6464bde3, 0x662203ba, 0x67e0698d, + 0x48d7cb20, 0x4915a117, 0x4b531f4e, 0x4a917579, 0x4fde63fc, 0x4e1c09cb, 0x4c5ab792, 0x4d98dda5, 0x46c49a98, 0x4706f0af, 0x45404ef6, 0x448224c1, 0x41cd3244, 0x400f5873, 0x4249e62a, 0x438b8c1d, + 0x54f16850, 0x55330267, 0x5775bc3e, 0x56b7d609, 0x53f8c08c, 0x523aaabb, 0x507c14e2, 0x51be7ed5, 0x5ae239e8, 0x5b2053df, 0x5966ed86, 0x58a487b1, 0x5deb9134, 0x5c29fb03, 0x5e6f455a, 0x5fad2f6d, + 0xe1351b80, 0xe0f771b7, 0xe2b1cfee, 0xe373a5d9, 0xe63cb35c, 0xe7fed96b, 0xe5b86732, 0xe47a0d05, 0xef264a38, 0xeee4200f, 0xeca29e56, 0xed60f461, 0xe82fe2e4, 0xe9ed88d3, 0xebab368a, 0xea695cbd, + 0xfd13b8f0, 0xfcd1d2c7, 0xfe976c9e, 0xff5506a9, 0xfa1a102c, 0xfbd87a1b, 0xf99ec442, 0xf85cae75, 0xf300e948, 0xf2c2837f, 0xf0843d26, 0xf1465711, 0xf4094194, 0xf5cb2ba3, 0xf78d95fa, 0xf64fffcd, + 0xd9785d60, 0xd8ba3757, 0xdafc890e, 0xdb3ee339, 0xde71f5bc, 0xdfb39f8b, 0xddf521d2, 0xdc374be5, 0xd76b0cd8, 0xd6a966ef, 0xd4efd8b6, 0xd52db281, 0xd062a404, 0xd1a0ce33, 0xd3e6706a, 0xd2241a5d, + 0xc55efe10, 0xc49c9427, 0xc6da2a7e, 0xc7184049, 0xc25756cc, 0xc3953cfb, 0xc1d382a2, 0xc011e895, 0xcb4dafa8, 0xca8fc59f, 0xc8c97bc6, 0xc90b11f1, 0xcc440774, 0xcd866d43, 0xcfc0d31a, 0xce02b92d, + 0x91af9640, 0x906dfc77, 0x922b422e, 0x93e92819, 0x96a63e9c, 0x976454ab, 0x9522eaf2, 0x94e080c5, 0x9fbcc7f8, 0x9e7eadcf, 0x9c381396, 0x9dfa79a1, 0x98b56f24, 0x99770513, 0x9b31bb4a, 0x9af3d17d, + 0x8d893530, 0x8c4b5f07, 0x8e0de15e, 0x8fcf8b69, 0x8a809dec, 0x8b42f7db, 0x89044982, 0x88c623b5, 0x839a6488, 0x82580ebf, 0x801eb0e6, 0x81dcdad1, 0x8493cc54, 0x8551a663, 0x8717183a, 0x86d5720d, + 0xa9e2d0a0, 0xa820ba97, 0xaa6604ce, 0xaba46ef9, 0xaeeb787c, 0xaf29124b, 0xad6fac12, 0xacadc625, 0xa7f18118, 0xa633eb2f, 0xa4755576, 0xa5b73f41, 0xa0f829c4, 0xa13a43f3, 0xa37cfdaa, 0xa2be979d, + 0xb5c473d0, 0xb40619e7, 0xb640a7be, 0xb782cd89, 0xb2cddb0c, 0xb30fb13b, 0xb1490f62, 0xb08b6555, 0xbbd72268, 0xba15485f, 0xb853f606, 0xb9919c31, 0xbcde8ab4, 0xbd1ce083, 0xbf5a5eda, 0xbe9834ed + }, + { + 0x00000000, 0xb8bc6765, 0xaa09c88b, 0x12b5afee, 0x8f629757, 0x37def032, 0x256b5fdc, 0x9dd738b9, 0xc5b428ef, 0x7d084f8a, 0x6fbde064, 0xd7018701, 0x4ad6bfb8, 0xf26ad8dd, 0xe0df7733, 0x58631056, + 0x5019579f, 0xe8a530fa, 0xfa109f14, 0x42acf871, 0xdf7bc0c8, 0x67c7a7ad, 0x75720843, 0xcdce6f26, 0x95ad7f70, 0x2d111815, 0x3fa4b7fb, 0x8718d09e, 0x1acfe827, 0xa2738f42, 0xb0c620ac, 0x087a47c9, + 0xa032af3e, 0x188ec85b, 0x0a3b67b5, 0xb28700d0, 0x2f503869, 0x97ec5f0c, 0x8559f0e2, 0x3de59787, 0x658687d1, 0xdd3ae0b4, 0xcf8f4f5a, 0x7733283f, 0xeae41086, 0x525877e3, 0x40edd80d, 0xf851bf68, + 0xf02bf8a1, 0x48979fc4, 0x5a22302a, 0xe29e574f, 0x7f496ff6, 0xc7f50893, 0xd540a77d, 0x6dfcc018, 0x359fd04e, 0x8d23b72b, 0x9f9618c5, 0x272a7fa0, 0xbafd4719, 0x0241207c, 0x10f48f92, 0xa848e8f7, + 0x9b14583d, 0x23a83f58, 0x311d90b6, 0x89a1f7d3, 0x1476cf6a, 0xaccaa80f, 0xbe7f07e1, 0x06c36084, 0x5ea070d2, 0xe61c17b7, 0xf4a9b859, 0x4c15df3c, 0xd1c2e785, 0x697e80e0, 0x7bcb2f0e, 0xc377486b, + 0xcb0d0fa2, 0x73b168c7, 0x6104c729, 0xd9b8a04c, 0x446f98f5, 0xfcd3ff90, 0xee66507e, 0x56da371b, 0x0eb9274d, 0xb6054028, 0xa4b0efc6, 0x1c0c88a3, 0x81dbb01a, 0x3967d77f, 0x2bd27891, 0x936e1ff4, + 0x3b26f703, 0x839a9066, 0x912f3f88, 0x299358ed, 0xb4446054, 0x0cf80731, 0x1e4da8df, 0xa6f1cfba, 0xfe92dfec, 0x462eb889, 0x549b1767, 0xec277002, 0x71f048bb, 0xc94c2fde, 0xdbf98030, 0x6345e755, + 0x6b3fa09c, 0xd383c7f9, 0xc1366817, 0x798a0f72, 0xe45d37cb, 0x5ce150ae, 0x4e54ff40, 0xf6e89825, 0xae8b8873, 0x1637ef16, 0x048240f8, 0xbc3e279d, 0x21e91f24, 0x99557841, 0x8be0d7af, 0x335cb0ca, + 0xed59b63b, 0x55e5d15e, 0x47507eb0, 0xffec19d5, 0x623b216c, 0xda874609, 0xc832e9e7, 0x708e8e82, 0x28ed9ed4, 0x9051f9b1, 0x82e4565f, 0x3a58313a, 0xa78f0983, 0x1f336ee6, 0x0d86c108, 0xb53aa66d, + 0xbd40e1a4, 0x05fc86c1, 0x1749292f, 0xaff54e4a, 0x322276f3, 0x8a9e1196, 0x982bbe78, 0x2097d91d, 0x78f4c94b, 0xc048ae2e, 0xd2fd01c0, 0x6a4166a5, 0xf7965e1c, 0x4f2a3979, 0x5d9f9697, 0xe523f1f2, + 0x4d6b1905, 0xf5d77e60, 0xe762d18e, 0x5fdeb6eb, 0xc2098e52, 0x7ab5e937, 0x680046d9, 0xd0bc21bc, 0x88df31ea, 0x3063568f, 0x22d6f961, 0x9a6a9e04, 0x07bda6bd, 0xbf01c1d8, 0xadb46e36, 0x15080953, + 0x1d724e9a, 0xa5ce29ff, 0xb77b8611, 0x0fc7e174, 0x9210d9cd, 0x2aacbea8, 0x38191146, 0x80a57623, 0xd8c66675, 0x607a0110, 0x72cfaefe, 0xca73c99b, 0x57a4f122, 0xef189647, 0xfdad39a9, 0x45115ecc, + 0x764dee06, 0xcef18963, 0xdc44268d, 0x64f841e8, 0xf92f7951, 0x41931e34, 0x5326b1da, 0xeb9ad6bf, 0xb3f9c6e9, 0x0b45a18c, 0x19f00e62, 0xa14c6907, 0x3c9b51be, 0x842736db, 0x96929935, 0x2e2efe50, + 0x2654b999, 0x9ee8defc, 0x8c5d7112, 0x34e11677, 0xa9362ece, 0x118a49ab, 0x033fe645, 0xbb838120, 0xe3e09176, 0x5b5cf613, 0x49e959fd, 0xf1553e98, 0x6c820621, 0xd43e6144, 0xc68bceaa, 0x7e37a9cf, + 0xd67f4138, 0x6ec3265d, 0x7c7689b3, 0xc4caeed6, 0x591dd66f, 0xe1a1b10a, 0xf3141ee4, 0x4ba87981, 0x13cb69d7, 0xab770eb2, 0xb9c2a15c, 0x017ec639, 0x9ca9fe80, 0x241599e5, 0x36a0360b, 0x8e1c516e, + 0x866616a7, 0x3eda71c2, 0x2c6fde2c, 0x94d3b949, 0x090481f0, 0xb1b8e695, 0xa30d497b, 0x1bb12e1e, 0x43d23e48, 0xfb6e592d, 0xe9dbf6c3, 0x516791a6, 0xccb0a91f, 0x740cce7a, 0x66b96194, 0xde0506f1 + }, + { + 0x00000000, 0x3d6029b0, 0x7ac05360, 0x47a07ad0, 0xf580a6c0, 0xc8e08f70, 0x8f40f5a0, 0xb220dc10, 0x30704bc1, 0x0d106271, 0x4ab018a1, 0x77d03111, 0xc5f0ed01, 0xf890c4b1, 0xbf30be61, 0x825097d1, + 0x60e09782, 0x5d80be32, 0x1a20c4e2, 0x2740ed52, 0x95603142, 0xa80018f2, 0xefa06222, 0xd2c04b92, 0x5090dc43, 0x6df0f5f3, 0x2a508f23, 0x1730a693, 0xa5107a83, 0x98705333, 0xdfd029e3, 0xe2b00053, + 0xc1c12f04, 0xfca106b4, 0xbb017c64, 0x866155d4, 0x344189c4, 0x0921a074, 0x4e81daa4, 0x73e1f314, 0xf1b164c5, 0xccd14d75, 0x8b7137a5, 0xb6111e15, 0x0431c205, 0x3951ebb5, 0x7ef19165, 0x4391b8d5, + 0xa121b886, 0x9c419136, 0xdbe1ebe6, 0xe681c256, 0x54a11e46, 0x69c137f6, 0x2e614d26, 0x13016496, 0x9151f347, 0xac31daf7, 0xeb91a027, 0xd6f18997, 0x64d15587, 0x59b17c37, 0x1e1106e7, 0x23712f57, + 0x58f35849, 0x659371f9, 0x22330b29, 0x1f532299, 0xad73fe89, 0x9013d739, 0xd7b3ade9, 0xead38459, 0x68831388, 0x55e33a38, 0x124340e8, 0x2f236958, 0x9d03b548, 0xa0639cf8, 0xe7c3e628, 0xdaa3cf98, + 0x3813cfcb, 0x0573e67b, 0x42d39cab, 0x7fb3b51b, 0xcd93690b, 0xf0f340bb, 0xb7533a6b, 0x8a3313db, 0x0863840a, 0x3503adba, 0x72a3d76a, 0x4fc3feda, 0xfde322ca, 0xc0830b7a, 0x872371aa, 0xba43581a, + 0x9932774d, 0xa4525efd, 0xe3f2242d, 0xde920d9d, 0x6cb2d18d, 0x51d2f83d, 0x167282ed, 0x2b12ab5d, 0xa9423c8c, 0x9422153c, 0xd3826fec, 0xeee2465c, 0x5cc29a4c, 0x61a2b3fc, 0x2602c92c, 0x1b62e09c, + 0xf9d2e0cf, 0xc4b2c97f, 0x8312b3af, 0xbe729a1f, 0x0c52460f, 0x31326fbf, 0x7692156f, 0x4bf23cdf, 0xc9a2ab0e, 0xf4c282be, 0xb362f86e, 0x8e02d1de, 0x3c220dce, 0x0142247e, 0x46e25eae, 0x7b82771e, + 0xb1e6b092, 0x8c869922, 0xcb26e3f2, 0xf646ca42, 0x44661652, 0x79063fe2, 0x3ea64532, 0x03c66c82, 0x8196fb53, 0xbcf6d2e3, 0xfb56a833, 0xc6368183, 0x74165d93, 0x49767423, 0x0ed60ef3, 0x33b62743, + 0xd1062710, 0xec660ea0, 0xabc67470, 0x96a65dc0, 0x248681d0, 0x19e6a860, 0x5e46d2b0, 0x6326fb00, 0xe1766cd1, 0xdc164561, 0x9bb63fb1, 0xa6d61601, 0x14f6ca11, 0x2996e3a1, 0x6e369971, 0x5356b0c1, + 0x70279f96, 0x4d47b626, 0x0ae7ccf6, 0x3787e546, 0x85a73956, 0xb8c710e6, 0xff676a36, 0xc2074386, 0x4057d457, 0x7d37fde7, 0x3a978737, 0x07f7ae87, 0xb5d77297, 0x88b75b27, 0xcf1721f7, 0xf2770847, + 0x10c70814, 0x2da721a4, 0x6a075b74, 0x576772c4, 0xe547aed4, 0xd8278764, 0x9f87fdb4, 0xa2e7d404, 0x20b743d5, 0x1dd76a65, 0x5a7710b5, 0x67173905, 0xd537e515, 0xe857cca5, 0xaff7b675, 0x92979fc5, + 0xe915e8db, 0xd475c16b, 0x93d5bbbb, 0xaeb5920b, 0x1c954e1b, 0x21f567ab, 0x66551d7b, 0x5b3534cb, 0xd965a31a, 0xe4058aaa, 0xa3a5f07a, 0x9ec5d9ca, 0x2ce505da, 0x11852c6a, 0x562556ba, 0x6b457f0a, + 0x89f57f59, 0xb49556e9, 0xf3352c39, 0xce550589, 0x7c75d999, 0x4115f029, 0x06b58af9, 0x3bd5a349, 0xb9853498, 0x84e51d28, 0xc34567f8, 0xfe254e48, 0x4c059258, 0x7165bbe8, 0x36c5c138, 0x0ba5e888, + 0x28d4c7df, 0x15b4ee6f, 0x521494bf, 0x6f74bd0f, 0xdd54611f, 0xe03448af, 0xa794327f, 0x9af41bcf, 0x18a48c1e, 0x25c4a5ae, 0x6264df7e, 0x5f04f6ce, 0xed242ade, 0xd044036e, 0x97e479be, 0xaa84500e, + 0x4834505d, 0x755479ed, 0x32f4033d, 0x0f942a8d, 0xbdb4f69d, 0x80d4df2d, 0xc774a5fd, 0xfa148c4d, 0x78441b9c, 0x4524322c, 0x028448fc, 0x3fe4614c, 0x8dc4bd5c, 0xb0a494ec, 0xf704ee3c, 0xca64c78c + }, + { + 0x00000000, 0xcb5cd3a5, 0x4dc8a10b, 0x869472ae, 0x9b914216, 0x50cd91b3, 0xd659e31d, 0x1d0530b8, 0xec53826d, 0x270f51c8, 0xa19b2366, 0x6ac7f0c3, 0x77c2c07b, 0xbc9e13de, 0x3a0a6170, 0xf156b2d5, + 0x03d6029b, 0xc88ad13e, 0x4e1ea390, 0x85427035, 0x9847408d, 0x531b9328, 0xd58fe186, 0x1ed33223, 0xef8580f6, 0x24d95353, 0xa24d21fd, 0x6911f258, 0x7414c2e0, 0xbf481145, 0x39dc63eb, 0xf280b04e, + 0x07ac0536, 0xccf0d693, 0x4a64a43d, 0x81387798, 0x9c3d4720, 0x57619485, 0xd1f5e62b, 0x1aa9358e, 0xebff875b, 0x20a354fe, 0xa6372650, 0x6d6bf5f5, 0x706ec54d, 0xbb3216e8, 0x3da66446, 0xf6fab7e3, + 0x047a07ad, 0xcf26d408, 0x49b2a6a6, 0x82ee7503, 0x9feb45bb, 0x54b7961e, 0xd223e4b0, 0x197f3715, 0xe82985c0, 0x23755665, 0xa5e124cb, 0x6ebdf76e, 0x73b8c7d6, 0xb8e41473, 0x3e7066dd, 0xf52cb578, + 0x0f580a6c, 0xc404d9c9, 0x4290ab67, 0x89cc78c2, 0x94c9487a, 0x5f959bdf, 0xd901e971, 0x125d3ad4, 0xe30b8801, 0x28575ba4, 0xaec3290a, 0x659ffaaf, 0x789aca17, 0xb3c619b2, 0x35526b1c, 0xfe0eb8b9, + 0x0c8e08f7, 0xc7d2db52, 0x4146a9fc, 0x8a1a7a59, 0x971f4ae1, 0x5c439944, 0xdad7ebea, 0x118b384f, 0xe0dd8a9a, 0x2b81593f, 0xad152b91, 0x6649f834, 0x7b4cc88c, 0xb0101b29, 0x36846987, 0xfdd8ba22, + 0x08f40f5a, 0xc3a8dcff, 0x453cae51, 0x8e607df4, 0x93654d4c, 0x58399ee9, 0xdeadec47, 0x15f13fe2, 0xe4a78d37, 0x2ffb5e92, 0xa96f2c3c, 0x6233ff99, 0x7f36cf21, 0xb46a1c84, 0x32fe6e2a, 0xf9a2bd8f, + 0x0b220dc1, 0xc07ede64, 0x46eaacca, 0x8db67f6f, 0x90b34fd7, 0x5bef9c72, 0xdd7beedc, 0x16273d79, 0xe7718fac, 0x2c2d5c09, 0xaab92ea7, 0x61e5fd02, 0x7ce0cdba, 0xb7bc1e1f, 0x31286cb1, 0xfa74bf14, + 0x1eb014d8, 0xd5ecc77d, 0x5378b5d3, 0x98246676, 0x852156ce, 0x4e7d856b, 0xc8e9f7c5, 0x03b52460, 0xf2e396b5, 0x39bf4510, 0xbf2b37be, 0x7477e41b, 0x6972d4a3, 0xa22e0706, 0x24ba75a8, 0xefe6a60d, + 0x1d661643, 0xd63ac5e6, 0x50aeb748, 0x9bf264ed, 0x86f75455, 0x4dab87f0, 0xcb3ff55e, 0x006326fb, 0xf135942e, 0x3a69478b, 0xbcfd3525, 0x77a1e680, 0x6aa4d638, 0xa1f8059d, 0x276c7733, 0xec30a496, + 0x191c11ee, 0xd240c24b, 0x54d4b0e5, 0x9f886340, 0x828d53f8, 0x49d1805d, 0xcf45f2f3, 0x04192156, 0xf54f9383, 0x3e134026, 0xb8873288, 0x73dbe12d, 0x6eded195, 0xa5820230, 0x2316709e, 0xe84aa33b, + 0x1aca1375, 0xd196c0d0, 0x5702b27e, 0x9c5e61db, 0x815b5163, 0x4a0782c6, 0xcc93f068, 0x07cf23cd, 0xf6999118, 0x3dc542bd, 0xbb513013, 0x700de3b6, 0x6d08d30e, 0xa65400ab, 0x20c07205, 0xeb9ca1a0, + 0x11e81eb4, 0xdab4cd11, 0x5c20bfbf, 0x977c6c1a, 0x8a795ca2, 0x41258f07, 0xc7b1fda9, 0x0ced2e0c, 0xfdbb9cd9, 0x36e74f7c, 0xb0733dd2, 0x7b2fee77, 0x662adecf, 0xad760d6a, 0x2be27fc4, 0xe0beac61, + 0x123e1c2f, 0xd962cf8a, 0x5ff6bd24, 0x94aa6e81, 0x89af5e39, 0x42f38d9c, 0xc467ff32, 0x0f3b2c97, 0xfe6d9e42, 0x35314de7, 0xb3a53f49, 0x78f9ecec, 0x65fcdc54, 0xaea00ff1, 0x28347d5f, 0xe368aefa, + 0x16441b82, 0xdd18c827, 0x5b8cba89, 0x90d0692c, 0x8dd55994, 0x46898a31, 0xc01df89f, 0x0b412b3a, 0xfa1799ef, 0x314b4a4a, 0xb7df38e4, 0x7c83eb41, 0x6186dbf9, 0xaada085c, 0x2c4e7af2, 0xe712a957, + 0x15921919, 0xdececabc, 0x585ab812, 0x93066bb7, 0x8e035b0f, 0x455f88aa, 0xc3cbfa04, 0x089729a1, 0xf9c19b74, 0x329d48d1, 0xb4093a7f, 0x7f55e9da, 0x6250d962, 0xa90c0ac7, 0x2f987869, 0xe4c4abcc + }, + { + 0x00000000, 0xa6770bb4, 0x979f1129, 0x31e81a9d, 0xf44f2413, 0x52382fa7, 0x63d0353a, 0xc5a73e8e, 0x33ef4e67, 0x959845d3, 0xa4705f4e, 0x020754fa, 0xc7a06a74, 0x61d761c0, 0x503f7b5d, 0xf64870e9, + 0x67de9cce, 0xc1a9977a, 0xf0418de7, 0x56368653, 0x9391b8dd, 0x35e6b369, 0x040ea9f4, 0xa279a240, 0x5431d2a9, 0xf246d91d, 0xc3aec380, 0x65d9c834, 0xa07ef6ba, 0x0609fd0e, 0x37e1e793, 0x9196ec27, + 0xcfbd399c, 0x69ca3228, 0x582228b5, 0xfe552301, 0x3bf21d8f, 0x9d85163b, 0xac6d0ca6, 0x0a1a0712, 0xfc5277fb, 0x5a257c4f, 0x6bcd66d2, 0xcdba6d66, 0x081d53e8, 0xae6a585c, 0x9f8242c1, 0x39f54975, + 0xa863a552, 0x0e14aee6, 0x3ffcb47b, 0x998bbfcf, 0x5c2c8141, 0xfa5b8af5, 0xcbb39068, 0x6dc49bdc, 0x9b8ceb35, 0x3dfbe081, 0x0c13fa1c, 0xaa64f1a8, 0x6fc3cf26, 0xc9b4c492, 0xf85cde0f, 0x5e2bd5bb, + 0x440b7579, 0xe27c7ecd, 0xd3946450, 0x75e36fe4, 0xb044516a, 0x16335ade, 0x27db4043, 0x81ac4bf7, 0x77e43b1e, 0xd19330aa, 0xe07b2a37, 0x460c2183, 0x83ab1f0d, 0x25dc14b9, 0x14340e24, 0xb2430590, + 0x23d5e9b7, 0x85a2e203, 0xb44af89e, 0x123df32a, 0xd79acda4, 0x71edc610, 0x4005dc8d, 0xe672d739, 0x103aa7d0, 0xb64dac64, 0x87a5b6f9, 0x21d2bd4d, 0xe47583c3, 0x42028877, 0x73ea92ea, 0xd59d995e, + 0x8bb64ce5, 0x2dc14751, 0x1c295dcc, 0xba5e5678, 0x7ff968f6, 0xd98e6342, 0xe86679df, 0x4e11726b, 0xb8590282, 0x1e2e0936, 0x2fc613ab, 0x89b1181f, 0x4c162691, 0xea612d25, 0xdb8937b8, 0x7dfe3c0c, + 0xec68d02b, 0x4a1fdb9f, 0x7bf7c102, 0xdd80cab6, 0x1827f438, 0xbe50ff8c, 0x8fb8e511, 0x29cfeea5, 0xdf879e4c, 0x79f095f8, 0x48188f65, 0xee6f84d1, 0x2bc8ba5f, 0x8dbfb1eb, 0xbc57ab76, 0x1a20a0c2, + 0x8816eaf2, 0x2e61e146, 0x1f89fbdb, 0xb9fef06f, 0x7c59cee1, 0xda2ec555, 0xebc6dfc8, 0x4db1d47c, 0xbbf9a495, 0x1d8eaf21, 0x2c66b5bc, 0x8a11be08, 0x4fb68086, 0xe9c18b32, 0xd82991af, 0x7e5e9a1b, + 0xefc8763c, 0x49bf7d88, 0x78576715, 0xde206ca1, 0x1b87522f, 0xbdf0599b, 0x8c184306, 0x2a6f48b2, 0xdc27385b, 0x7a5033ef, 0x4bb82972, 0xedcf22c6, 0x28681c48, 0x8e1f17fc, 0xbff70d61, 0x198006d5, + 0x47abd36e, 0xe1dcd8da, 0xd034c247, 0x7643c9f3, 0xb3e4f77d, 0x1593fcc9, 0x247be654, 0x820cede0, 0x74449d09, 0xd23396bd, 0xe3db8c20, 0x45ac8794, 0x800bb91a, 0x267cb2ae, 0x1794a833, 0xb1e3a387, + 0x20754fa0, 0x86024414, 0xb7ea5e89, 0x119d553d, 0xd43a6bb3, 0x724d6007, 0x43a57a9a, 0xe5d2712e, 0x139a01c7, 0xb5ed0a73, 0x840510ee, 0x22721b5a, 0xe7d525d4, 0x41a22e60, 0x704a34fd, 0xd63d3f49, + 0xcc1d9f8b, 0x6a6a943f, 0x5b828ea2, 0xfdf58516, 0x3852bb98, 0x9e25b02c, 0xafcdaab1, 0x09baa105, 0xfff2d1ec, 0x5985da58, 0x686dc0c5, 0xce1acb71, 0x0bbdf5ff, 0xadcafe4b, 0x9c22e4d6, 0x3a55ef62, + 0xabc30345, 0x0db408f1, 0x3c5c126c, 0x9a2b19d8, 0x5f8c2756, 0xf9fb2ce2, 0xc813367f, 0x6e643dcb, 0x982c4d22, 0x3e5b4696, 0x0fb35c0b, 0xa9c457bf, 0x6c636931, 0xca146285, 0xfbfc7818, 0x5d8b73ac, + 0x03a0a617, 0xa5d7ada3, 0x943fb73e, 0x3248bc8a, 0xf7ef8204, 0x519889b0, 0x6070932d, 0xc6079899, 0x304fe870, 0x9638e3c4, 0xa7d0f959, 0x01a7f2ed, 0xc400cc63, 0x6277c7d7, 0x539fdd4a, 0xf5e8d6fe, + 0x647e3ad9, 0xc209316d, 0xf3e12bf0, 0x55962044, 0x90311eca, 0x3646157e, 0x07ae0fe3, 0xa1d90457, 0x579174be, 0xf1e67f0a, 0xc00e6597, 0x66796e23, 0xa3de50ad, 0x05a95b19, 0x34414184, 0x92364a30 + }, + { + 0x00000000, 0xccaa009e, 0x4225077d, 0x8e8f07e3, 0x844a0efa, 0x48e00e64, 0xc66f0987, 0x0ac50919, 0xd3e51bb5, 0x1f4f1b2b, 0x91c01cc8, 0x5d6a1c56, 0x57af154f, 0x9b0515d1, 0x158a1232, 0xd92012ac, + 0x7cbb312b, 0xb01131b5, 0x3e9e3656, 0xf23436c8, 0xf8f13fd1, 0x345b3f4f, 0xbad438ac, 0x767e3832, 0xaf5e2a9e, 0x63f42a00, 0xed7b2de3, 0x21d12d7d, 0x2b142464, 0xe7be24fa, 0x69312319, 0xa59b2387, + 0xf9766256, 0x35dc62c8, 0xbb53652b, 0x77f965b5, 0x7d3c6cac, 0xb1966c32, 0x3f196bd1, 0xf3b36b4f, 0x2a9379e3, 0xe639797d, 0x68b67e9e, 0xa41c7e00, 0xaed97719, 0x62737787, 0xecfc7064, 0x205670fa, + 0x85cd537d, 0x496753e3, 0xc7e85400, 0x0b42549e, 0x01875d87, 0xcd2d5d19, 0x43a25afa, 0x8f085a64, 0x562848c8, 0x9a824856, 0x140d4fb5, 0xd8a74f2b, 0xd2624632, 0x1ec846ac, 0x9047414f, 0x5ced41d1, + 0x299dc2ed, 0xe537c273, 0x6bb8c590, 0xa712c50e, 0xadd7cc17, 0x617dcc89, 0xeff2cb6a, 0x2358cbf4, 0xfa78d958, 0x36d2d9c6, 0xb85dde25, 0x74f7debb, 0x7e32d7a2, 0xb298d73c, 0x3c17d0df, 0xf0bdd041, + 0x5526f3c6, 0x998cf358, 0x1703f4bb, 0xdba9f425, 0xd16cfd3c, 0x1dc6fda2, 0x9349fa41, 0x5fe3fadf, 0x86c3e873, 0x4a69e8ed, 0xc4e6ef0e, 0x084cef90, 0x0289e689, 0xce23e617, 0x40ace1f4, 0x8c06e16a, + 0xd0eba0bb, 0x1c41a025, 0x92cea7c6, 0x5e64a758, 0x54a1ae41, 0x980baedf, 0x1684a93c, 0xda2ea9a2, 0x030ebb0e, 0xcfa4bb90, 0x412bbc73, 0x8d81bced, 0x8744b5f4, 0x4beeb56a, 0xc561b289, 0x09cbb217, + 0xac509190, 0x60fa910e, 0xee7596ed, 0x22df9673, 0x281a9f6a, 0xe4b09ff4, 0x6a3f9817, 0xa6959889, 0x7fb58a25, 0xb31f8abb, 0x3d908d58, 0xf13a8dc6, 0xfbff84df, 0x37558441, 0xb9da83a2, 0x7570833c, + 0x533b85da, 0x9f918544, 0x111e82a7, 0xddb48239, 0xd7718b20, 0x1bdb8bbe, 0x95548c5d, 0x59fe8cc3, 0x80de9e6f, 0x4c749ef1, 0xc2fb9912, 0x0e51998c, 0x04949095, 0xc83e900b, 0x46b197e8, 0x8a1b9776, + 0x2f80b4f1, 0xe32ab46f, 0x6da5b38c, 0xa10fb312, 0xabcaba0b, 0x6760ba95, 0xe9efbd76, 0x2545bde8, 0xfc65af44, 0x30cfafda, 0xbe40a839, 0x72eaa8a7, 0x782fa1be, 0xb485a120, 0x3a0aa6c3, 0xf6a0a65d, + 0xaa4de78c, 0x66e7e712, 0xe868e0f1, 0x24c2e06f, 0x2e07e976, 0xe2ade9e8, 0x6c22ee0b, 0xa088ee95, 0x79a8fc39, 0xb502fca7, 0x3b8dfb44, 0xf727fbda, 0xfde2f2c3, 0x3148f25d, 0xbfc7f5be, 0x736df520, + 0xd6f6d6a7, 0x1a5cd639, 0x94d3d1da, 0x5879d144, 0x52bcd85d, 0x9e16d8c3, 0x1099df20, 0xdc33dfbe, 0x0513cd12, 0xc9b9cd8c, 0x4736ca6f, 0x8b9ccaf1, 0x8159c3e8, 0x4df3c376, 0xc37cc495, 0x0fd6c40b, + 0x7aa64737, 0xb60c47a9, 0x3883404a, 0xf42940d4, 0xfeec49cd, 0x32464953, 0xbcc94eb0, 0x70634e2e, 0xa9435c82, 0x65e95c1c, 0xeb665bff, 0x27cc5b61, 0x2d095278, 0xe1a352e6, 0x6f2c5505, 0xa386559b, + 0x061d761c, 0xcab77682, 0x44387161, 0x889271ff, 0x825778e6, 0x4efd7878, 0xc0727f9b, 0x0cd87f05, 0xd5f86da9, 0x19526d37, 0x97dd6ad4, 0x5b776a4a, 0x51b26353, 0x9d1863cd, 0x1397642e, 0xdf3d64b0, + 0x83d02561, 0x4f7a25ff, 0xc1f5221c, 0x0d5f2282, 0x079a2b9b, 0xcb302b05, 0x45bf2ce6, 0x89152c78, 0x50353ed4, 0x9c9f3e4a, 0x121039a9, 0xdeba3937, 0xd47f302e, 0x18d530b0, 0x965a3753, 0x5af037cd, + 0xff6b144a, 0x33c114d4, 0xbd4e1337, 0x71e413a9, 0x7b211ab0, 0xb78b1a2e, 0x39041dcd, 0xf5ae1d53, 0x2c8e0fff, 0xe0240f61, 0x6eab0882, 0xa201081c, 0xa8c40105, 0x646e019b, 0xeae10678, 0x264b06e6 + } + }; + } +} diff --git a/Translation/UAssetAPI/CustomVersion.cs b/Translation/UAssetAPI/CustomVersion.cs new file mode 100644 index 0000000..a6680be --- /dev/null +++ b/Translation/UAssetAPI/CustomVersion.cs @@ -0,0 +1,1109 @@ +using System; +using System.Collections.Generic; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI +{ + /// + /// A custom version. Controls more specific serialization than the main engine object version does. + /// + public class CustomVersion + { + /// + /// Static map of custom version GUIDs to the object or enum that they represent in the Unreal Engine. This list is not necessarily exhaustive, so feel free to add to it if need be. + /// + public static readonly Dictionary GuidToCustomVersionStringMap = new Dictionary() + { + { UnusedCustomVersionKey, "UnusedCustomVersionKey" }, + { UAPUtils.GUID(0xB0D832E4, 0x1F894F0D, 0xACCF7EB7, 0x36FD4AA2), "FBlueprintsObjectVersion" }, + { UAPUtils.GUID(0xE1C64328, 0xA22C4D53, 0xA36C8E86, 0x6417BD8C), "FBuildObjectVersion" }, + { UAPUtils.GUID(0x375EC13C, 0x06E448FB, 0xB50084F0, 0x262A717E), "FCoreObjectVersion" }, + { UAPUtils.GUID(0xE4B068ED, 0xF49442E9, 0xA231DA0B, 0x2E46BB41), "FEditorObjectVersion" }, + { UAPUtils.GUID(0xCFFC743F, 0x43B04480, 0x939114DF, 0x171D2073), "FFrameworkObjectVersion" }, + { UAPUtils.GUID(0xB02B49B5, 0xBB2044E9, 0xA30432B7, 0x52E40360), "FMobileObjectVersion" }, + { UAPUtils.GUID(0xA4E4105C, 0x59A149B5, 0xA7C540C4, 0x547EDFEE), "FNetworkingObjectVersion" }, + { UAPUtils.GUID(0x39C831C9, 0x5AE647DC, 0x9A449C17, 0x3E1C8E7C), "FOnlineObjectVersion" }, + { UAPUtils.GUID(0x78F01B33, 0xEBEA4F98, 0xB9B484EA, 0xCCB95AA2), "FPhysicsObjectVersion" }, + { UAPUtils.GUID(0x6631380F, 0x2D4D43E0, 0x8009CF27, 0x6956A95A), "FPlatformObjectVersion" }, + { UAPUtils.GUID(0x12F88B9F, 0x88754AFC, 0xA67CD90C, 0x383ABD29), "FRenderingObjectVersion" }, + { UAPUtils.GUID(0x7B5AE74C, 0xD2704C10, 0xA9585798, 0x0B212A5A), "FSequencerObjectVersion" }, + { UAPUtils.GUID(0xD7296918, 0x1DD64BDD, 0x9DE264A8, 0x3CC13884), "FVRObjectVersion" }, + { UAPUtils.GUID(0xC2A15278, 0xBFE74AFE, 0x6C1790FF, 0x531DF755), "FLoadTimesObjectVersion" }, + { UAPUtils.GUID(0x6EACA3D4, 0x40EC4CC1, 0xb7868BED, 0x9428FC5), "FGeometryObjectVersion" }, + { UAPUtils.GUID(0x29E575DD, 0xE0A34627, 0x9D10D276, 0x232CDCEA), "FAnimPhysObjectVersion" }, + { UAPUtils.GUID(0xAF43A65D, 0x7FD34947, 0x98733E8E, 0xD9C1BB05), "FAnimObjectVersion" }, + { UAPUtils.GUID(0x6B266CEC, 0x1EC74B8F, 0xA30BE4D9, 0x0942FC07), "FReflectionCaptureObjectVersion" }, + { UAPUtils.GUID(0x0DF73D61, 0xA23F47EA, 0xB72789E9, 0x0C41499A), "FAutomationObjectVersion" }, + { UAPUtils.GUID(0x601D1886, 0xAC644F84, 0xAA16D3DE, 0x0DEAC7D6), "FFortniteMainBranchObjectVersion" }, + { UAPUtils.GUID(0x9DFFBCD6, 0x494F0158, 0xE2211282, 0x3C92A888), "FEnterpriseObjectVersion" }, + { UAPUtils.GUID(0xF2AED0AC, 0x9AFE416F, 0x8664AA7F, 0xFA26D6FC), "FNiagaraObjectVersion" }, + { UAPUtils.GUID(0x174F1F0B, 0xB4C645A5, 0xB13F2EE8, 0xD0FB917D), "FDestructionObjectVersion" }, + { UAPUtils.GUID(0x35F94A83, 0xE258406C, 0xA31809F5, 0x9610247C), "FExternalPhysicsCustomObjectVersion" }, + { UAPUtils.GUID(0xB68FC16E, 0x8B1B42E2, 0xB453215C, 0x058844FE), "FExternalPhysicsMaterialCustomObjectVersion" }, + { UAPUtils.GUID(0xB2E18506, 0x4273CFC2, 0xA54EF4BB, 0x758BBA07), "FCineCameraObjectVersion" }, + { UAPUtils.GUID(0x64F58936, 0xFD1B42BA, 0xBA967289, 0xD5D0FA4E), "FVirtualProductionObjectVersion" }, + { UAPUtils.GUID(0x6f0ed827, 0xa6094895, 0x9c91998d, 0x90180ea4), "FMediaFrameworkObjectVersion" }, + { UAPUtils.GUID(0xAFE08691, 0x3A0D4952, 0xB673673B, 0x7CF22D1E), "FPoseDriverCustomVersion" }, + { UAPUtils.GUID(0xCB8AB0CD, 0xE78C4BDE, 0xA8621393, 0x14E9EF62), "FTempCustomVersion" }, + { UAPUtils.GUID(0x2EB5FDBD, 0x01AC4D10, 0x8136F38F, 0x3393A5DA), "FAnimationCustomVersion" }, + { UAPUtils.GUID(0x717F9EE7, 0xE9B0493A, 0x88B39132, 0x1B388107), "FAssetRegistryVersion" }, + { UAPUtils.GUID(0xFB680AF2, 0x59EF4BA3, 0xBAA819B5, 0x73C8443D), "FClothingAssetCustomVersion" }, + { UAPUtils.GUID(0x9C54D522, 0xA8264FBE, 0x94210746, 0x61B482D0), "FReleaseObjectVersion" }, + { UAPUtils.GUID(0x4A56EB40, 0x10F511DC, 0x92D3347E, 0xB2C96AE7), "FParticleSystemCustomVersion" }, + { UAPUtils.GUID(0xD78A4A00, 0xE8584697, 0xBAA819B5, 0x487D46B4), "FSkeletalMeshCustomVersion" }, + { UAPUtils.GUID(0x5579F886, 0x933A4C1F, 0x83BA087B, 0x6361B92F), "FRecomputeTangentCustomVersion" }, + { UAPUtils.GUID(0x612FBE52, 0xDA53400B, 0x910D4F91, 0x9FB1857C), "FOverlappingVerticesCustomVersion" }, + { UAPUtils.GUID(0x430C4D19, 0x71544970, 0x87699B69, 0xDF90B0E5), "FFoliageCustomVersion" }, + { UAPUtils.GUID(0xaafe32bd, 0x53954c14, 0xb66a5e25, 0x1032d1dd), "FProceduralFoliageCustomVersion" }, + { UAPUtils.GUID(0xab965196, 0x45d808fc, 0xb7d7228d, 0x78ad569e), "FLiveLinkCustomVersion" }, + // etc. + }; + + /// + /// A GUID that represents an unused custom version. + /// + public static readonly Guid UnusedCustomVersionKey = UAPUtils.GUID(0, 0, 0, 0xF99D40C1); + + /// + /// Returns the name of the object or enum that a custom version GUID represents, as specified in . + /// + /// A GUID that represents a custom version. + /// A string that represents the friendly name of the corresponding custom version. + public static string GetCustomVersionFriendlyNameFromGuid(Guid guid) + { + return GuidToCustomVersionStringMap.ContainsKey(guid) ? GuidToCustomVersionStringMap[guid] : null; + } + + /// + /// Returns the GUID of the custom version that the object or enum name provided represents. + /// + /// The name of a custom version object or enum. + /// A GUID that represents the custom version + public static Guid GetCustomVersionGuidFromFriendlyName(string friendlyName) + { + foreach (KeyValuePair entry in GuidToCustomVersionStringMap) + { + if (entry.Value == friendlyName) return entry.Key; + } + return UnusedCustomVersionKey; + } + + public Guid Key; + public string FriendlyName = null; + public int Version; + + /// + /// Initializes a new instance of the class given an object or enum name and a version number. + /// + /// The friendly name to use when initializing this custom version. + /// The version number to use when initializing this custom version. + public CustomVersion(string friendlyName, int version) + { + Key = GetCustomVersionGuidFromFriendlyName(friendlyName); + FriendlyName = friendlyName; + Version = version; + } + + /// + /// Initializes a new instance of the class given a custom version GUID and a version number. + /// + /// The GUID to use when initializing this custom version. + /// The version number to use when initializing this custom version. + public CustomVersion(Guid key, int version) + { + Key = key; + if (GuidToCustomVersionStringMap.ContainsKey(key)) FriendlyName = GuidToCustomVersionStringMap[key]; + Version = version; + } + + /// + /// Initializes a new instance of the class. + /// + public CustomVersion() + { + Key = UnusedCustomVersionKey; + Version = 0; + } + } + + /* Below are some enums of custom versions we need for serialization */ + + /// + /// Represents the engine version at the time that a custom version was implemented. + /// + [AttributeUsage(AttributeTargets.Field)] + public class IntroducedAttribute : Attribute + { + public UE4Version IntroducedVersion; + + public IntroducedAttribute(UE4Version introducedVersion) + { + IntroducedVersion = introducedVersion; + } + } + + /// + /// Custom serialization version for changes made in the //Fortnite/Main stream. + /// + public enum FFortniteMainBranchObjectVersion + { + /// Before any version changes were made + [Introduced(UE4Version.VER_UE4_OLDEST_LOADABLE_PACKAGE)] + BeforeCustomVersionWasAdded = 0, + + /// World composition tile offset changed from 2d to 3d + [Introduced(UE4Version.VER_UE4_ADDED_PACKAGE_SUMMARY_LOCALIZATION_ID)] + WorldCompositionTile3DOffset, + + /// Minor material serialization optimization + [Introduced(UE4Version.VER_UE4_ADDED_PACKAGE_SUMMARY_LOCALIZATION_ID)] + MaterialInstanceSerializeOptimization_ShaderFName, + + /// Refactored cull distances to account for HLOD, explicit override and globals in priority + [Introduced(UE4Version.VER_UE4_ADDED_PACKAGE_SUMMARY_LOCALIZATION_ID)] + CullDistanceRefactor_RemovedDefaultDistance, + [Introduced(UE4Version.VER_UE4_ADDED_PACKAGE_SUMMARY_LOCALIZATION_ID)] + CullDistanceRefactor_NeverCullHLODsByDefault, + [Introduced(UE4Version.VER_UE4_ADDED_PACKAGE_SUMMARY_LOCALIZATION_ID)] + CullDistanceRefactor_NeverCullALODActorsByDefault, + + /// Support to remove morphtarget generated by bRemapMorphtarget + [Introduced(UE4Version.VER_UE4_ADDED_PACKAGE_SUMMARY_LOCALIZATION_ID)] + SaveGeneratedMorphTargetByEngine, + + /// Convert reduction setting options + [Introduced(UE4Version.VER_UE4_ADDED_PACKAGE_SUMMARY_LOCALIZATION_ID)] + ConvertReductionSettingOptions, + + /// Serialize the type of blending used for landscape layer weight static params + [Introduced(UE4Version.VER_UE4_ADDED_PACKAGE_SUMMARY_LOCALIZATION_ID)] + StaticParameterTerrainLayerWeightBlendType, + + /// Fix up None Named animation curve names, + [Introduced(UE4Version.VER_UE4_ADDED_PACKAGE_SUMMARY_LOCALIZATION_ID)] + FixUpNoneNameAnimationCurves, + + /// Ensure ActiveBoneIndices to have parents even not skinned for old assets + [Introduced(UE4Version.VER_UE4_ADDED_PACKAGE_SUMMARY_LOCALIZATION_ID)] + EnsureActiveBoneIndicesToContainParents, + + /// Serialize the instanced static mesh render data, to avoid building it at runtime + [Introduced(UE4Version.VER_UE4_ADDED_PACKAGE_SUMMARY_LOCALIZATION_ID)] + SerializeInstancedStaticMeshRenderData, + + /// Cache material quality node usage + [Introduced(UE4Version.VER_UE4_ADDED_PACKAGE_SUMMARY_LOCALIZATION_ID)] + CachedMaterialQualityNodeUsage, + + /// Font outlines no longer apply to drop shadows for new objects but we maintain the opposite way for backwards compat + [Introduced(UE4Version.VER_UE4_ADDED_PACKAGE_SUMMARY_LOCALIZATION_ID)] + FontOutlineDropShadowFixup, + + /// New skeletal mesh import workflow (Geometry only or animation only re-import ) + [Introduced(UE4Version.VER_UE4_ADDED_PACKAGE_SUMMARY_LOCALIZATION_ID)] + NewSkeletalMeshImporterWorkflow, + + /// Migrate data from previous data structure to new one to support materials per LOD on the Landscape + [Introduced(UE4Version.VER_UE4_ADDED_PACKAGE_SUMMARY_LOCALIZATION_ID)] + NewLandscapeMaterialPerLOD, + + /// New Pose Asset data type + [Introduced(UE4Version.VER_UE4_ADDED_PACKAGE_SUMMARY_LOCALIZATION_ID)] + RemoveUnnecessaryTracksFromPose, + + /// Migrate Foliage TLazyObjectPtr to TSoftObjectPtr + [Introduced(UE4Version.VER_UE4_ADDED_PACKAGE_SUMMARY_LOCALIZATION_ID)] + FoliageLazyObjPtrToSoftObjPtr, + + /// TimelineTemplates store their derived names instead of dynamically generating. This code tied to this version was reverted and redone at a later date + [Introduced(UE4Version.VER_UE4_FIX_WIDE_STRING_CRC)] + REVERTED_StoreTimelineNamesInTemplate, + + /// Added BakePoseOverride for LOD setting + [Introduced(UE4Version.VER_UE4_FIX_WIDE_STRING_CRC)] + AddBakePoseOverrideForSkeletalMeshReductionSetting, + + /// TimelineTemplates store their derived names instead of dynamically generating + [Introduced(UE4Version.VER_UE4_FIX_WIDE_STRING_CRC)] + StoreTimelineNamesInTemplate, + + /// New Pose Asset data type + [Introduced(UE4Version.VER_UE4_FIX_WIDE_STRING_CRC)] + WidgetStopDuplicatingAnimations, + + /// Allow reducing of the base LOD, we need to store some imported model data so we can reduce again from the same data. + [Introduced(UE4Version.VER_UE4_FIX_WIDE_STRING_CRC)] + AllowSkeletalMeshToReduceTheBaseLOD, + + /// Curve Table size reduction + [Introduced(UE4Version.VER_UE4_FIX_WIDE_STRING_CRC)] + ShrinkCurveTableSize, + + /// Widgets upgraded with WidgetStopDuplicatingAnimations, may not correctly default-to-self for the widget parameter. + [Introduced(UE4Version.VER_UE4_FIX_WIDE_STRING_CRC)] + WidgetAnimationDefaultToSelfFail, + + /// HUDWidgets now require an element tag + [Introduced(UE4Version.VER_UE4_FIX_WIDE_STRING_CRC)] + FortHUDElementNowRequiresTag, + + /// Animation saved as bulk data when cooked + [Introduced(UE4Version.VER_UE4_FIX_WIDE_STRING_CRC)] + FortMappedCookedAnimation, + + /// Support Virtual Bone in Retarget Manager + [Introduced(UE4Version.VER_UE4_FIX_WIDE_STRING_CRC)] + SupportVirtualBoneInRetargeting, + + /// Fixup bad defaults in water metadata + [Introduced(UE4Version.VER_UE4_FIX_WIDE_STRING_CRC)] + FixUpWaterMetadata, + + /// Move the location of water metadata + [Introduced(UE4Version.VER_UE4_FIX_WIDE_STRING_CRC)] + MoveWaterMetadataToActor, + + /// Replaced lake collision component + [Introduced(UE4Version.VER_UE4_FIX_WIDE_STRING_CRC)] + ReplaceLakeCollision, + + /// Anim layer node names are now conformed by Guid + [Introduced(UE4Version.VER_UE4_ADDED_PACKAGE_OWNER)] + AnimLayerGuidConformation, + + /// Ocean collision component has become dynamic + [Introduced(UE4Version.VER_UE4_SKINWEIGHT_PROFILE_DATA_LAYOUT_CHANGES)] + MakeOceanCollisionTransient, + + /// FFieldPath will serialize the owner struct reference and only a short path to its property + [Introduced(UE4Version.VER_UE4_SKINWEIGHT_PROFILE_DATA_LAYOUT_CHANGES)] + FFieldPathOwnerSerialization, + + /// Simplified WaterBody post process material handling + [Introduced(UE4Version.VER_UE4_SKINWEIGHT_PROFILE_DATA_LAYOUT_CHANGES)] + FixUpUnderwaterPostProcessMaterial, + + /// A single water exclusion volume can now exclude N water bodies + [Introduced(UE4Version.VER_UE4_SKINWEIGHT_PROFILE_DATA_LAYOUT_CHANGES)] + SupportMultipleWaterBodiesPerExclusionVolume, + + /// Serialize rigvm operators one by one instead of the full byte code array to ensure determinism + [Introduced(UE4Version.VER_UE4_NON_OUTER_PACKAGE_IMPORT)] + RigVMByteCodeDeterminism, + + /// Serialize the physical materials generated by the render material + [Introduced(UE4Version.VER_UE4_NON_OUTER_PACKAGE_IMPORT)] + LandscapePhysicalMaterialRenderData, + + /// RuntimeVirtualTextureVolume fix transforms + [Introduced(UE4Version.VER_UE4_NON_OUTER_PACKAGE_IMPORT)] + FixupRuntimeVirtualTextureVolume, + + /// Retrieve water body collision components that were lost in cooked builds + [Introduced(UE4Version.VER_UE4_NON_OUTER_PACKAGE_IMPORT)] + FixUpRiverCollisionComponents, + + /// Fix duplicate spline mesh components on rivers + [Introduced(UE4Version.VER_UE4_NON_OUTER_PACKAGE_IMPORT)] + FixDuplicateRiverSplineMeshCollisionComponents, + + /// Indicates level has stable actor guids + [Introduced(UE4Version.VER_UE4_NON_OUTER_PACKAGE_IMPORT)] + ContainsStableActorGUIDs, + + /// Levelset Serialization support for BodySetup. + [Introduced(UE4Version.VER_UE4_NON_OUTER_PACKAGE_IMPORT)] + LevelsetSerializationSupportForBodySetup, + + /// Moving Chaos solver properties to allow them to exist in the project physics settings + [Introduced(UE4Version.VER_UE4_ASSETREGISTRY_DEPENDENCYFLAGS)] + ChaosSolverPropertiesMoved, + + /// Moving some UFortGameFeatureData properties and behaviors into the UGameFeatureAction pattern + [Introduced(UE4Version.VER_UE4_CORRECT_LICENSEE_FLAG)] + GameFeatureData_MovedComponentListAndCheats, + + /// Add centrifugal forces for cloth + [Introduced(UE4Version.VER_UE4_CORRECT_LICENSEE_FLAG)] + ChaosClothAddfictitiousforces, + + /// Chaos Convex StructureData supports different index sizes based on num verts/planes. Chaos FConvex uses array of FVec3s for vertices instead of particles (Merged from //UE4/Main) + [Introduced(UE4Version.VER_UE4_CORRECT_LICENSEE_FLAG)] + ChaosConvexVariableStructureDataAndVerticesArray, + + /// Remove the WaterVelocityHeightTexture dependency on MPC_Landscape and LandscapeWaterIndo + [Introduced(UE4Version.VER_UE4_CORRECT_LICENSEE_FLAG)] + RemoveLandscapeWaterInfo, + + [Introduced(UE4Version.VER_UE4_AUTOMATIC_VERSION_PLUS_ONE)] + VersionPlusOne, + [Introduced(UE4Version.VER_UE4_AUTOMATIC_VERSION)] + LatestVersion = VersionPlusOne - 1 + }; + + /// + /// Custom serialization version for changes made in Dev-Framework stream. + /// + public enum FFrameworkObjectVersion + { + /// Before any version changes were made + [Introduced(UE4Version.VER_UE4_OLDEST_LOADABLE_PACKAGE)] + BeforeCustomVersionWasAdded = 0, + + /// BodySetup's default instance collision profile is used by default when creating a new instance. + [Introduced(UE4Version.VER_UE4_STREAMABLE_TEXTURE_AABB)] + UseBodySetupCollisionProfile, + + /// Regenerate subgraph arrays correctly in animation blueprints to remove duplicates and add missing graphs that appear read only when edited + [Introduced(UE4Version.VER_UE4_PROPERTY_GUID_IN_PROPERTY_TAG)] + AnimBlueprintSubgraphFix, + + /// Static and skeletal mesh sockets now use the specified scale + [Introduced(UE4Version.VER_UE4_NAME_HASHES_SERIALIZED)] + MeshSocketScaleUtilization, + + /// Attachment rules are now explicit in how they affect location, rotation and scale + [Introduced(UE4Version.VER_UE4_NAME_HASHES_SERIALIZED)] + ExplicitAttachmentRules, + + /// Moved compressed anim data from uasset to the DDC + [Introduced(UE4Version.VER_UE4_NAME_HASHES_SERIALIZED)] + MoveCompressedAnimDataToTheDDC, + + /// Some graph pins created using legacy code seem to have lost the RF_Transactional flag, which causes issues with undo. Restore the flag at this version + [Introduced(UE4Version.VER_UE4_NAME_HASHES_SERIALIZED)] + FixNonTransactionalPins, + + /// Create new struct for SmartName, and use that for CurveName + [Introduced(UE4Version.VER_UE4_NAME_HASHES_SERIALIZED)] + SmartNameRefactor, + + /// Add Reference Skeleton to Rig + [Introduced(UE4Version.VER_UE4_NAME_HASHES_SERIALIZED)] + AddSourceReferenceSkeletonToRig, + + /// Refactor ConstraintInstance so that we have an easy way to swap behavior paramters + [Introduced(UE4Version.VER_UE4_INSTANCED_STEREO_UNIFORM_REFACTOR)] + ConstraintInstanceBehaviorParameters, + + /// Pose Asset support mask per bone + [Introduced(UE4Version.VER_UE4_INSTANCED_STEREO_UNIFORM_REFACTOR)] + PoseAssetSupportPerBoneMask, + + /// Physics Assets now use SkeletalBodySetup instead of BodySetup + [Introduced(UE4Version.VER_UE4_INSTANCED_STEREO_UNIFORM_REFACTOR)] + PhysAssetUseSkeletalBodySetup, + + /// Remove SoundWave CompressionName + [Introduced(UE4Version.VER_UE4_INSTANCED_STEREO_UNIFORM_REFACTOR)] + RemoveSoundWaveCompressionName, + + /// Switched render data for clothing over to unreal data, reskinned to the simulation mesh + [Introduced(UE4Version.VER_UE4_INSTANCED_STEREO_UNIFORM_REFACTOR)] + AddInternalClothingGraphicalSkinning, + + /// Wheel force offset is now applied at the wheel instead of vehicle COM + [Introduced(UE4Version.VER_UE4_INSTANCED_STEREO_UNIFORM_REFACTOR)] + WheelOffsetIsFromWheel, + + /// Move curve metadata to be saved in skeleton. Individual asset still saves some flag - i.e. disabled curve and editable or not, but major flag - i.e. material types - moves to skeleton and handle in one place + [Introduced(UE4Version.VER_UE4_COMPRESSED_SHADER_RESOURCES)] + MoveCurveTypesToSkeleton, + + /// Cache destructible overlaps on save + [Introduced(UE4Version.VER_UE4_TemplateIndex_IN_COOKED_EXPORTS)] + CacheDestructibleOverlaps, + + /// Added serialization of materials applied to geometry cache objects + [Introduced(UE4Version.VER_UE4_TemplateIndex_IN_COOKED_EXPORTS)] + GeometryCacheMissingMaterials, + + /// Switch static and skeletal meshes to calculate LODs based on resolution-independent screen size + [Introduced(UE4Version.VER_UE4_ADDED_SEARCHABLE_NAMES)] + LODsUseResolutionIndependentScreenSize, + + /// Blend space post load verification + [Introduced(UE4Version.VER_UE4_ADDED_SEARCHABLE_NAMES)] + BlendSpacePostLoadSnapToGrid, + + /// Addition of rate scales to blend space samples + [Introduced(UE4Version.VER_UE4_ADDED_SEARCHABLE_NAMES)] + SupportBlendSpaceRateScale, + + /// LOD hysteresis also needs conversion from the LODsUseResolutionIndependentScreenSize version + [Introduced(UE4Version.VER_UE4_ADDED_SEARCHABLE_NAMES)] + LODHysteresisUseResolutionIndependentScreenSize, + + /// AudioComponent override subtitle priority default change + [Introduced(UE4Version.VER_UE4_ADDED_SEARCHABLE_NAMES)] + ChangeAudioComponentOverrideSubtitlePriorityDefault, + + /// Serialize hard references to sound files when possible + [Introduced(UE4Version.VER_UE4_64BIT_EXPORTMAP_SERIALSIZES)] + HardSoundReferences, + + /// Enforce const correctness in Animation Blueprint function graphs + [Introduced(UE4Version.VER_UE4_ADDED_SWEEP_WHILE_WALKING_FLAG)] + EnforceConstInAnimBlueprintFunctionGraphs, + + /// Upgrade the InputKeySelector to use a text style + [Introduced(UE4Version.VER_UE4_ADDED_SWEEP_WHILE_WALKING_FLAG)] + InputKeySelectorTextStyle, + + /// Represent a pins container type as an enum not 3 independent booleans + [Introduced(UE4Version.VER_UE4_ADDED_SWEEP_WHILE_WALKING_FLAG)] + EdGraphPinContainerType, + + /// Switch asset pins to store as string instead of hard object reference + [Introduced(UE4Version.VER_UE4_ADDED_SWEEP_WHILE_WALKING_FLAG)] + ChangeAssetPinsToString, + + /// Fix Local Variables so that the properties are correctly flagged as blueprint visible + [Introduced(UE4Version.VER_UE4_ADDED_SWEEP_WHILE_WALKING_FLAG)] + LocalVariablesBlueprintVisible, + + /// Stopped serializing UField_Next so that UFunctions could be serialized in dependently of a UClass in order to allow us to do all UFunction loading in a single pass (after classes and CDOs are created) + [Introduced(UE4Version.VER_UE4_ADDED_SOFT_OBJECT_PATH)] + RemoveUField_Next, + + /// Fix User Defined structs so that all members are correct flagged blueprint visible + [Introduced(UE4Version.VER_UE4_ADDED_SOFT_OBJECT_PATH)] + UserDefinedStructsBlueprintVisible, + + /// FMaterialInput and FEdGraphPin store their name as FName instead of FString + [Introduced(UE4Version.VER_UE4_POINTLIGHT_SOURCE_ORIENTATION)] + PinsStoreFName, + + /// User defined structs store their default instance, which is used for initializing instances + [Introduced(UE4Version.VER_UE4_POINTLIGHT_SOURCE_ORIENTATION)] + UserDefinedStructsStoreDefaultInstance, + + /// Function terminator nodes serialize an FMemberReference rather than a name/class pair + [Introduced(UE4Version.VER_UE4_ADDED_PACKAGE_SUMMARY_LOCALIZATION_ID)] + FunctionTerminatorNodesUseMemberReference, + + /// Custom event and non-native interface event implementations add 'const' to reference parameters + [Introduced(UE4Version.VER_UE4_ADDED_PACKAGE_SUMMARY_LOCALIZATION_ID)] + EditableEventsUseConstRefParameters, + + /// No longer serialize the legacy flag that indicates this state, as it is now implied since we don't serialize the skeleton CDO + [Introduced(UE4Version.VER_UE4_FIX_WIDE_STRING_CRC)] + BlueprintGeneratedClassIsAlwaysAuthoritative, + + /// Enforce visibility of blueprint functions - e.g. raise an error if calling a private function from another blueprint: + [Introduced(UE4Version.VER_UE4_ADDED_PACKAGE_OWNER)] + EnforceBlueprintFunctionVisibility, + + /// ActorComponents now store their serialization index + [Introduced(UE4Version.VER_UE4_ADDED_PACKAGE_OWNER)] + StoringUCSSerializationIndex, + + [Introduced(UE4Version.VER_UE4_AUTOMATIC_VERSION_PLUS_ONE)] + VersionPlusOne, + [Introduced(UE4Version.VER_UE4_AUTOMATIC_VERSION)] + LatestVersion = VersionPlusOne - 1 + }; + + /// + /// Custom serialization version for changes made in Dev-Core stream. + /// + public enum FCoreObjectVersion + { + /// Before any version changes were made + [Introduced(UE4Version.VER_UE4_OLDEST_LOADABLE_PACKAGE)] + BeforeCustomVersionWasAdded = 0, + + [Introduced(UE4Version.VER_UE4_PROPERTY_GUID_IN_PROPERTY_TAG)] + MaterialInputNativeSerialize, + + [Introduced(UE4Version.VER_UE4_ADDED_SEARCHABLE_NAMES)] + EnumProperties, + + [Introduced(UE4Version.VER_UE4_FIX_WIDE_STRING_CRC)] + SkeletalMaterialEditorDataStripping, + + [Introduced(UE4Version.VER_UE4_ADDED_PACKAGE_OWNER)] + FProperties, + + [Introduced(UE4Version.VER_UE4_AUTOMATIC_VERSION_PLUS_ONE)] + VersionPlusOne, + [Introduced(UE4Version.VER_UE4_AUTOMATIC_VERSION)] + LatestVersion = VersionPlusOne - 1 + }; + + /// + /// Custom serialization version for changes made in Dev-Editor stream. + /// + public enum FEditorObjectVersion + { + /// Before any version changes were made + [Introduced(UE4Version.VER_UE4_OLDEST_LOADABLE_PACKAGE)] + BeforeCustomVersionWasAdded = 0, + + /// Localizable text gathered and stored in packages is now flagged with a localizable text gathering process version + [Introduced(UE4Version.VER_UE4_STREAMABLE_TEXTURE_AABB)] + GatheredTextProcessVersionFlagging, + + /// Fixed several issues with the gathered text cache stored in package headers + [Introduced(UE4Version.VER_UE4_NAME_HASHES_SERIALIZED)] + GatheredTextPackageCacheFixesV1, + + /// Added support for "root" meta-data (meta-data not associated with a particular object in a package) + [Introduced(UE4Version.VER_UE4_INSTANCED_STEREO_UNIFORM_REFACTOR)] + RootMetaDataSupport, + + /// Fixed issues with how Blueprint bytecode was cached + [Introduced(UE4Version.VER_UE4_INSTANCED_STEREO_UNIFORM_REFACTOR)] + GatheredTextPackageCacheFixesV2, + + /// Updated FFormatArgumentData to allow variant data to be marshaled from a BP into C++ + [Introduced(UE4Version.VER_UE4_INSTANCED_STEREO_UNIFORM_REFACTOR)] + TextFormatArgumentDataIsVariant, + + /// Changes to SplineComponent + [Introduced(UE4Version.VER_UE4_INSTANCED_STEREO_UNIFORM_REFACTOR)] + SplineComponentCurvesInStruct, + + /// Updated ComboBox to support toggling the menu open, better controller support + [Introduced(UE4Version.VER_UE4_COMPRESSED_SHADER_RESOURCES)] + ComboBoxControllerSupportUpdate, + + /// Refactor mesh editor materials + [Introduced(UE4Version.VER_UE4_COMPRESSED_SHADER_RESOURCES)] + RefactorMeshEditorMaterials, + + /// Added UFontFace assets + [Introduced(UE4Version.VER_UE4_TemplateIndex_IN_COOKED_EXPORTS)] + AddedFontFaceAssets, + + /// Add UPROPERTY for TMap of Mesh section, so the serialize will be done normally (and export to text will work correctly) + [Introduced(UE4Version.VER_UE4_ADDED_SEARCHABLE_NAMES)] + UPropertryForMeshSection, + + /// Update the schema of all widget blueprints to use the WidgetGraphSchema + [Introduced(UE4Version.VER_UE4_ADDED_SEARCHABLE_NAMES)] + WidgetGraphSchema, + + /// Added a specialized content slot to the background blur widget + [Introduced(UE4Version.VER_UE4_ADDED_SEARCHABLE_NAMES)] + AddedBackgroundBlurContentSlot, + + /// Updated UserDefinedEnums to have stable keyed display names + [Introduced(UE4Version.VER_UE4_ADDED_SEARCHABLE_NAMES)] + StableUserDefinedEnumDisplayNames, + + /// Added "Inline" option to UFontFace assets + [Introduced(UE4Version.VER_UE4_ADDED_SEARCHABLE_NAMES)] + AddedInlineFontFaceAssets, + + /// Fix a serialization issue with static mesh FMeshSectionInfoMap FProperty + [Introduced(UE4Version.VER_UE4_ADDED_SEARCHABLE_NAMES)] + UPropertryForMeshSectionSerialize, + + /// Adding a version bump for the new fast widget construction in case of problems. + [Introduced(UE4Version.VER_UE4_64BIT_EXPORTMAP_SERIALSIZES)] + FastWidgetTemplates, + + /// Update material thumbnails to be more intelligent on default primitive shape for certain material types + [Introduced(UE4Version.VER_UE4_64BIT_EXPORTMAP_SERIALSIZES)] + MaterialThumbnailRenderingChanges, + + /// Introducing a new clipping system for Slate/UMG + [Introduced(UE4Version.VER_UE4_ADDED_SWEEP_WHILE_WALKING_FLAG)] + NewSlateClippingSystem, + + /// MovieScene Meta Data added as native Serialization + [Introduced(UE4Version.VER_UE4_ADDED_SWEEP_WHILE_WALKING_FLAG)] + MovieSceneMetaDataSerialization, + + /// Text gathered from properties now adds two variants: a version without the package localization ID (for use at runtime), and a version with it (which is editor-only) + [Introduced(UE4Version.VER_UE4_ADDED_SWEEP_WHILE_WALKING_FLAG)] + GatheredTextEditorOnlyPackageLocId, + + /// Added AlwaysSign to FNumberFormattingOptions + [Introduced(UE4Version.VER_UE4_ADDED_SOFT_OBJECT_PATH)] + AddedAlwaysSignNumberFormattingOption, + + /// Added additional objects that must be serialized as part of this new material feature + [Introduced(UE4Version.VER_UE4_ADDED_PACKAGE_SUMMARY_LOCALIZATION_ID)] + AddedMaterialSharedInputs, + + /// Added morph target section indices + [Introduced(UE4Version.VER_UE4_ADDED_PACKAGE_SUMMARY_LOCALIZATION_ID)] + AddedMorphTargetSectionIndices, + + /// Serialize the instanced static mesh render data, to avoid building it at runtime + [Introduced(UE4Version.VER_UE4_ADDED_PACKAGE_SUMMARY_LOCALIZATION_ID)] + SerializeInstancedStaticMeshRenderData, + + /// Change to MeshDescription serialization (moved to release) + [Introduced(UE4Version.VER_UE4_ADDED_PACKAGE_SUMMARY_LOCALIZATION_ID)] + MeshDescriptionNewSerialization_MovedToRelease, + + /// New format for mesh description attributes + [Introduced(UE4Version.VER_UE4_ADDED_PACKAGE_SUMMARY_LOCALIZATION_ID)] + MeshDescriptionNewAttributeFormat, + + /// Switch root component of SceneCapture actors from MeshComponent to SceneComponent + [Introduced(UE4Version.VER_UE4_FIX_WIDE_STRING_CRC)] + ChangeSceneCaptureRootComponent, + + /// StaticMesh serializes MeshDescription instead of RawMesh + [Introduced(UE4Version.VER_UE4_FIX_WIDE_STRING_CRC)] + StaticMeshDeprecatedRawMesh, + + /// MeshDescriptionBulkData contains a Guid used as a DDC key + [Introduced(UE4Version.VER_UE4_FIX_WIDE_STRING_CRC)] + MeshDescriptionBulkDataGuid, + + /// Change to MeshDescription serialization (removed FMeshPolygon::HoleContours) + [Introduced(UE4Version.VER_UE4_FIX_WIDE_STRING_CRC)] + MeshDescriptionRemovedHoles, + + /// Change to the WidgetCompoent WindowVisibilty default value + [Introduced(UE4Version.VER_UE4_FILLER_22)] + ChangedWidgetComponentWindowVisibilityDefault, + + /// Avoid keying culture invariant display strings during serialization to avoid non-deterministic cooking issues + [Introduced(UE4Version.VER_UE4_FILLER_22)] + CultureInvariantTextSerializationKeyStability, + + /// Change to UScrollBar and UScrollBox thickness property (removed implicit padding of 2, so thickness value must be incremented by 4). + [Introduced(UE4Version.VER_UE4_FILLER_22)] + ScrollBarThicknessChange, + + /// Deprecated LandscapeHoleMaterial + [Introduced(UE4Version.VER_UE4_FILLER_22)] + RemoveLandscapeHoleMaterial, + + /// MeshDescription defined by triangles instead of arbitrary polygons + [Introduced(UE4Version.VER_UE4_FILLER_22)] + MeshDescriptionTriangles, + + /// Add weighted area and angle when computing the normals + [Introduced(UE4Version.VER_UE4_ADDED_PACKAGE_OWNER)] + ComputeWeightedNormals, + + /// SkeletalMesh now can be rebuild in editor, no more need to re-import + [Introduced(UE4Version.VER_UE4_ADDED_PACKAGE_OWNER)] + SkeletalMeshBuildRefactor, + + /// Move all SkeletalMesh source data into a private uasset in the same package has the skeletalmesh + [Introduced(UE4Version.VER_UE4_ADDED_PACKAGE_OWNER)] + SkeletalMeshMoveEditorSourceDataToPrivateAsset, + + /// Parse text only if the number is inside the limits of its type + [Introduced(UE4Version.VER_UE4_NON_OUTER_PACKAGE_IMPORT)] + NumberParsingOptionsNumberLimitsAndClamping, + + /// Make sure we can have more then 255 material in the skeletal mesh source data + [Introduced(UE4Version.VER_UE4_NON_OUTER_PACKAGE_IMPORT)] + SkeletalMeshSourceDataSupport16bitOfMaterialNumber, + + [Introduced(UE4Version.VER_UE4_AUTOMATIC_VERSION_PLUS_ONE)] + VersionPlusOne, + [Introduced(UE4Version.VER_UE4_AUTOMATIC_VERSION)] + LatestVersion = VersionPlusOne - 1 + }; + + /// + /// Custom serialization version for changes made in Dev-AnimPhys stream + /// + public enum FAnimPhysObjectVersion + { + /// Before any version changes were made + [Introduced(UE4Version.VER_UE4_OLDEST_LOADABLE_PACKAGE)] + BeforeCustomVersionWasAdded, + + /// convert animnode look at to use just default axis instead of enum, which doesn't do much + [Introduced(UE4Version.VER_UE4_ADDED_SWEEP_WHILE_WALKING_FLAG)] + ConvertAnimNodeLookAtAxis, + + /// Change FKSphylElem and FKBoxElem to use Rotators not Quats for easier editing + [Introduced(UE4Version.VER_UE4_ADDED_SWEEP_WHILE_WALKING_FLAG)] + BoxSphylElemsUseRotators, + + /// Change thumbnail scene info and asset import data to be transactional + [Introduced(UE4Version.VER_UE4_ADDED_SWEEP_WHILE_WALKING_FLAG)] + ThumbnailSceneInfoAndAssetImportDataAreTransactional, + + /// Enabled clothing masks rather than painting parameters directly + [Introduced(UE4Version.VER_UE4_ADDED_SWEEP_WHILE_WALKING_FLAG)] + AddedClothingMaskWorkflow, + + /// Remove UID from smart name serialize, it just breaks determinism + [Introduced(UE4Version.VER_UE4_ADDED_SWEEP_WHILE_WALKING_FLAG)] + RemoveUIDFromSmartNameSerialize, + + /// Convert FName Socket to FSocketReference and added TargetReference that support bone and socket + [Introduced(UE4Version.VER_UE4_ADDED_SWEEP_WHILE_WALKING_FLAG)] + CreateTargetReference, + + /// Tune soft limit stiffness and damping coefficients + [Introduced(UE4Version.VER_UE4_ADDED_SWEEP_WHILE_WALKING_FLAG)] + TuneSoftLimitStiffnessAndDamping, + + /// Fix possible inf/nans in clothing particle masses + [Introduced(UE4Version.VER_UE4_ADDED_SWEEP_WHILE_WALKING_FLAG)] + FixInvalidClothParticleMasses, + + /// Moved influence count to cached data + [Introduced(UE4Version.VER_UE4_ADDED_SWEEP_WHILE_WALKING_FLAG)] + CacheClothMeshInfluences, + + /// Remove GUID from Smart Names entirely + remove automatic name fixup + [Introduced(UE4Version.VER_UE4_ADDED_SOFT_OBJECT_PATH)] + SmartNameRefactorForDeterministicCooking, + + /// rename the variable and allow individual curves to be set + [Introduced(UE4Version.VER_UE4_ADDED_SOFT_OBJECT_PATH)] + RenameDisableAnimCurvesToAllowAnimCurveEvaluation, + + /// link curve to LOD, so curve metadata has to include LODIndex + [Introduced(UE4Version.VER_UE4_ADDED_SOFT_OBJECT_PATH)] + AddLODToCurveMetaData, + + /// Fixed blend profile references persisting after paste when they aren't compatible + [Introduced(UE4Version.VER_UE4_ADDED_SOFT_OBJECT_PATH)] + FixupBadBlendProfileReferences, + + /// Allowing multiple audio plugin settings + [Introduced(UE4Version.VER_UE4_ADDED_SOFT_OBJECT_PATH)] + AllowMultipleAudioPluginSettings, + + /// Change RetargetSource reference to SoftObjectPtr + [Introduced(UE4Version.VER_UE4_POINTLIGHT_SOURCE_ORIENTATION)] + ChangeRetargetSourceReferenceToSoftObjectPtr, + + /// Save editor only full pose for pose asset + [Introduced(UE4Version.VER_UE4_POINTLIGHT_SOURCE_ORIENTATION)] + SaveEditorOnlyFullPoseForPoseAsset, + + /// Asset change and cleanup to facilitate new streaming system + [Introduced(UE4Version.VER_UE4_ADDED_PACKAGE_SUMMARY_LOCALIZATION_ID)] + GeometryCacheAssetDeprecation, + + [Introduced(UE4Version.VER_UE4_AUTOMATIC_VERSION_PLUS_ONE)] + VersionPlusOne, + [Introduced(UE4Version.VER_UE4_AUTOMATIC_VERSION)] + LatestVersion = VersionPlusOne - 1 + } + + /// + /// Custom serialization version for changes made in Release streams. + /// + public enum FReleaseObjectVersion + { + /// Before any version changes were made + [Introduced(UE4Version.VER_UE4_OLDEST_LOADABLE_PACKAGE)] + BeforeCustomVersionWasAdded = 0, + + /// Static Mesh extended bounds radius fix + [Introduced(UE4Version.VER_UE4_NAME_HASHES_SERIALIZED)] + StaticMeshExtendedBoundsFix, + + /// Physics asset bodies are either in the sync scene or the async scene, but not both + [Introduced(UE4Version.VER_UE4_INSTANCED_STEREO_UNIFORM_REFACTOR)] + NoSyncAsyncPhysAsset, + + /// ULevel was using TTransArray incorrectly (serializing the entire array in addition to individual mutations). converted to a TArray + [Introduced(UE4Version.VER_UE4_INSTANCED_STEREO_UNIFORM_REFACTOR)] + LevelTransArrayConvertedToTArray, + + /// Add Component node templates now use their own unique naming scheme to ensure more reliable archetype lookups. + [Introduced(UE4Version.VER_UE4_TemplateIndex_IN_COOKED_EXPORTS)] + AddComponentNodeTemplateUniqueNames, + + /// Fix a serialization issue with static mesh FMeshSectionInfoMap FProperty + [Introduced(UE4Version.VER_UE4_ADDED_SEARCHABLE_NAMES)] + UPropertryForMeshSectionSerialize, + + /// Existing HLOD settings screen size to screen area conversion + [Introduced(UE4Version.VER_UE4_ADDED_SEARCHABLE_NAMES)] + ConvertHLODScreenSize, + + /// Adding mesh section info data for existing billboard LOD models + [Introduced(UE4Version.VER_UE4_ADDED_SEARCHABLE_NAMES)] + SpeedTreeBillboardSectionInfoFixup, + + /// Change FMovieSceneEventParameters::StructType to be a string asset reference from a TWeakObjectPtr UScriptStruct + [Introduced(UE4Version.VER_UE4_ADDED_SWEEP_WHILE_WALKING_FLAG)] + EventSectionParameterStringAssetRef, + + /// Remove serialized irradiance map data from skylight. + [Introduced(UE4Version.VER_UE4_ADDED_SWEEP_WHILE_WALKING_FLAG)] + SkyLightRemoveMobileIrradianceMap, + + /// rename bNoTwist to bAllowTwist + [Introduced(UE4Version.VER_UE4_ADDED_SWEEP_WHILE_WALKING_FLAG)] + RenameNoTwistToAllowTwistInTwoBoneIK, + + /// Material layers serialization refactor + [Introduced(UE4Version.VER_UE4_ADDED_PACKAGE_SUMMARY_LOCALIZATION_ID)] + MaterialLayersParameterSerializationRefactor, + + /// Added disable flag to skeletal mesh data + [Introduced(UE4Version.VER_UE4_ADDED_PACKAGE_SUMMARY_LOCALIZATION_ID)] + AddSkeletalMeshSectionDisable, + + /// Removed objects that were serialized as part of this material feature + [Introduced(UE4Version.VER_UE4_ADDED_PACKAGE_SUMMARY_LOCALIZATION_ID)] + RemovedMaterialSharedInputCollection, + + /// HISMC Cluster Tree migration to add new data + [Introduced(UE4Version.VER_UE4_ADDED_PACKAGE_SUMMARY_LOCALIZATION_ID)] + HISMCClusterTreeMigration, + + /// Default values on pins in blueprints could be saved incoherently + [Introduced(UE4Version.VER_UE4_ADDED_PACKAGE_SUMMARY_LOCALIZATION_ID)] + PinDefaultValuesVerified, + + /// During copy and paste transition getters could end up with broken state machine references + [Introduced(UE4Version.VER_UE4_ADDED_PACKAGE_SUMMARY_LOCALIZATION_ID)] + FixBrokenStateMachineReferencesInTransitionGetters, + + /// Change to MeshDescription serialization + [Introduced(UE4Version.VER_UE4_ADDED_PACKAGE_SUMMARY_LOCALIZATION_ID)] + MeshDescriptionNewSerialization, + + /// Change to not clamp RGB values > 1 on linear color curves + [Introduced(UE4Version.VER_UE4_ADDED_PACKAGE_SUMMARY_LOCALIZATION_ID)] + UnclampRGBColorCurves, + + /// Bugfix for FAnimObjectVersion::LinkTimeAnimBlueprintRootDiscovery. + [Introduced(UE4Version.VER_UE4_ADDED_PACKAGE_SUMMARY_LOCALIZATION_ID)] + LinkTimeAnimBlueprintRootDiscoveryBugFix, + + /// Change trail anim node variable deprecation + [Introduced(UE4Version.VER_UE4_ADDED_PACKAGE_SUMMARY_LOCALIZATION_ID)] + TrailNodeBlendVariableNameChange, + + /// Make sure the Blueprint Replicated Property Conditions are actually serialized properly. + [Introduced(UE4Version.VER_UE4_FIX_WIDE_STRING_CRC)] + PropertiesSerializeRepCondition, + + /// DepthOfFieldFocalDistance at 0 now disables DOF instead of DepthOfFieldFstop at 0. + [Introduced(UE4Version.VER_UE4_FIX_WIDE_STRING_CRC)] + FocalDistanceDisablesDOF, + + /// Removed versioning, but version entry must still exist to keep assets saved with this version loadable + [Introduced(UE4Version.VER_UE4_FIX_WIDE_STRING_CRC)] + Unused_SoundClass2DReverbSend, + + /// Groom asset version + [Introduced(UE4Version.VER_UE4_ADDED_PACKAGE_OWNER)] + GroomAssetVersion1, + + /// Groom asset version + [Introduced(UE4Version.VER_UE4_ADDED_PACKAGE_OWNER)] + GroomAssetVersion2, + + /// Store applied version of Animation Modifier to use when reverting + [Introduced(UE4Version.VER_UE4_ADDED_PACKAGE_OWNER)] + SerializeAnimModifierState, + + /// Groom asset version + [Introduced(UE4Version.VER_UE4_ADDED_PACKAGE_OWNER)] + GroomAssetVersion3, + + /// Upgrade filmback + [Introduced(UE4Version.VER_UE4_ADDED_PACKAGE_OWNER)] + DeprecateFilmbackSettings, + + /// custom collision type + [Introduced(UE4Version.VER_UE4_ADDED_PACKAGE_OWNER)] + CustomImplicitCollisionType, + + /// FFieldPath will serialize the owner struct reference and only a short path to its property + [Introduced(UE4Version.VER_UE4_ADDED_PACKAGE_OWNER)] + FFieldPathOwnerSerialization, + + /// Dummy version to allow us to fix up the fact that ReleaseObjectVersion was changed elsewhere + [Introduced(UE4Version.VER_UE4_SKINWEIGHT_PROFILE_DATA_LAYOUT_CHANGES)] + ReleaseObjectVersionFixup, + + /// Pin types include a flag that propagates the 'CPF_UObjectWrapper' flag to generated properties + [Introduced(UE4Version.VER_UE4_ASSETREGISTRY_DEPENDENCYFLAGS)] + PinTypeIncludesUObjectWrapperFlag, + + /// Added Weight member to FMeshToMeshVertData + [Introduced(UE4Version.VER_UE4_ASSETREGISTRY_DEPENDENCYFLAGS)] + WeightFMeshToMeshVertData, + + /// Animation graph node bindings displayed as pins + [Introduced(UE4Version.VER_UE4_ASSETREGISTRY_DEPENDENCYFLAGS)] + AnimationGraphNodeBindingsDisplayedAsPins, + + /// Serialized rigvm offset segment paths + [Introduced(UE4Version.VER_UE4_ASSETREGISTRY_DEPENDENCYFLAGS)] + SerializeRigVMOffsetSegmentPaths, + + /// Upgrade AbcGeomCacheImportSettings for velocities + [Introduced(UE4Version.VER_UE4_ASSETREGISTRY_DEPENDENCYFLAGS)] + AbcVelocitiesSupport, + + /// Add margin support to Chaos Convex + [Introduced(UE4Version.VER_UE4_ASSETREGISTRY_DEPENDENCYFLAGS)] + MarginAddedToConvexAndBox, + + /// Add structure data to Chaos Convex + [Introduced(UE4Version.VER_UE4_ASSETREGISTRY_DEPENDENCYFLAGS)] + StructureDataAddedToConvex, + + /// Changed axis UI for LiveLink AxisSwitch Pre Processor + [Introduced(UE4Version.VER_UE4_CORRECT_LICENSEE_FLAG)] + AddedFrontRightUpAxesToLiveLinkPreProcessor, + + /// Some sequencer event sections that were copy-pasted left broken links to the director BP + [Introduced(UE4Version.VER_UE4_CORRECT_LICENSEE_FLAG)] + FixupCopiedEventSections, + + /// Serialize the number of bytes written when serializing function arguments + [Introduced(UE4Version.VER_UE4_CORRECT_LICENSEE_FLAG)] + RemoteControlSerializeFunctionArgumentsSize, + + /// Add loop counters to sequencer's compiled sub-sequence data + [Introduced(UE4Version.VER_UE4_CORRECT_LICENSEE_FLAG)] + AddedSubSequenceEntryWarpCounter, + + /// Remove default resolution limit of 512 pixels for cubemaps generated from long-lat sources + [Introduced(UE4Version.VER_UE4_CORRECT_LICENSEE_FLAG)] + LonglatTextureCubeDefaultMaxResolution, + + /// bake center of mass into chaos cache + [Introduced(UE4Version.VER_UE4_CORRECT_LICENSEE_FLAG)] + GeometryCollectionCacheRemovesMassToLocal, + + [Introduced(UE4Version.VER_UE4_AUTOMATIC_VERSION_PLUS_ONE)] + VersionPlusOne, + [Introduced(UE4Version.VER_UE4_AUTOMATIC_VERSION)] + LatestVersion = VersionPlusOne - 1 + } + + /// + /// Version used for serializing asset registry caches, both runtime and editor + /// + public enum FAssetRegistryVersion + { + /// From before file versioning was implemented + [Introduced(UE4Version.VER_UE4_AUTOMATIC_VERSION)] + PreVersioning = 0, + + /// The first version of the runtime asset registry to include file versioning. + [Introduced(UE4Version.VER_UE4_AUTOMATIC_VERSION)] + HardSoftDependencies, + + /// Added FAssetRegistryState and support for piecemeal serialization + [Introduced(UE4Version.VER_UE4_AUTOMATIC_VERSION)] + AddAssetRegistryState, + + /// AssetData serialization format changed, versions before this are not readable + [Introduced(UE4Version.VER_UE4_AUTOMATIC_VERSION)] + ChangedAssetData, + + /// Removed MD5 hash from package data + [Introduced(UE4Version.VER_UE4_AUTOMATIC_VERSION)] + RemovedMD5Hash, + + /// Added hard/soft manage references + [Introduced(UE4Version.VER_UE4_AUTOMATIC_VERSION)] + AddedHardManage, + + /// Added MD5 hash of cooked package to package data + [Introduced(UE4Version.VER_UE4_AUTOMATIC_VERSION)] + AddedCookedMD5Hash, + + /// Added UE::AssetRegistry::EDependencyProperty to each dependency + [Introduced(UE4Version.VER_UE4_AUTOMATIC_VERSION)] + AddedDependencyFlags, + + /// Major tag format change that replaces USE_COMPACT_ASSET_REGISTRY: + [Introduced(UE4Version.VER_UE4_AUTOMATIC_VERSION)] + FixedTags, + + /// Added Version information to AssetPackageData + [Introduced(UE4Version.VER_UE4_AUTOMATIC_VERSION)] + WorkspaceDomain, + + /// Added ImportedClasses to AssetPackageData + [Introduced(UE4Version.VER_UE4_AUTOMATIC_VERSION)] + PackageImportedClasses, + + /// A new version number of UE5 was added to FPackageFileSummary + [Introduced(UE4Version.VER_UE4_AUTOMATIC_VERSION)] + PackageFileSummaryVersionChange, + + /// Change to linker export/import resource serializationn + [Introduced(UE4Version.VER_UE4_AUTOMATIC_VERSION)] + ObjectResourceOptionalVersionChange, + + [Introduced(UE4Version.VER_UE4_AUTOMATIC_VERSION_PLUS_ONE)] + VersionPlusOne, + [Introduced(UE4Version.VER_UE4_AUTOMATIC_VERSION)] + LatestVersion = VersionPlusOne - 1 + } + + public enum FSequencerObjectVersion + { + /// Before any version changes were made + [Introduced(UE4Version.VER_UE4_OLDEST_LOADABLE_PACKAGE)] + BeforeCustomVersionWasAdded = 0, + + /// Per-platform overrides player overrides for media sources changed name and type. + [Introduced(UE4Version.VER_UE4_OLDEST_LOADABLE_PACKAGE)] + RenameMediaSourcePlatformPlayers, + + /// Enable root motion isn't the right flag to use, but force root lock + [Introduced(UE4Version.VER_UE4_ADDED_SEARCHABLE_NAMES)] + ConvertEnableRootMotionToForceRootLock, + + /// Convert multiple rows to tracks + [Introduced(UE4Version.VER_UE4_ADDED_SEARCHABLE_NAMES)] + ConvertMultipleRowsToTracks, + + /// When finished now defaults to restore state + [Introduced(UE4Version.VER_UE4_64BIT_EXPORTMAP_SERIALSIZES)] + WhenFinishedDefaultsToRestoreState, + + /// EvaluationTree added + [Introduced(UE4Version.VER_UE4_64BIT_EXPORTMAP_SERIALSIZES)] + EvaluationTree, + + /// When finished now defaults to project default + [Introduced(UE4Version.VER_UE4_ADDED_SOFT_OBJECT_PATH)] + WhenFinishedDefaultsToProjectDefault, + + /// Use int range rather than float range in FMovieSceneSegment + [Introduced(UE4Version.VER_UE4_ADDED_PACKAGE_SUMMARY_LOCALIZATION_ID)] + FloatToIntConversion, + + /// Purged old spawnable blueprint classes from level sequence assets + [Introduced(UE4Version.VER_UE4_ADDED_PACKAGE_SUMMARY_LOCALIZATION_ID)] + PurgeSpawnableBlueprints, + + /// Finish UMG evaluation on end + [Introduced(UE4Version.VER_UE4_ADDED_PACKAGE_SUMMARY_LOCALIZATION_ID)] + FinishUMGEvaluation, + + /// Manual serialization of float channel + [Introduced(UE4Version.VER_UE4_FIX_WIDE_STRING_CRC)] + SerializeFloatChannel, + + /// Change the linear keys so they act the old way and interpolate always. + [Introduced(UE4Version.VER_UE4_FIX_WIDE_STRING_CRC)] + ModifyLinearKeysForOldInterp, + + /// Full Manual serialization of float channel + [Introduced(UE4Version.VER_UE4_ADDED_PACKAGE_OWNER)] + SerializeFloatChannelCompletely, + + /// Set ContinuouslyRespawn to false by default, added FMovieSceneSpawnable::bNetAddressableName + [Introduced(UE4Version.VER_UE4_ASSETREGISTRY_DEPENDENCYFLAGS)] + SpawnableImprovements, + + [Introduced(UE4Version.VER_UE4_AUTOMATIC_VERSION_PLUS_ONE)] + VersionPlusOne, + [Introduced(UE4Version.VER_UE4_AUTOMATIC_VERSION)] + LatestVersion = VersionPlusOne - 1 + } +} diff --git a/Translation/UAssetAPI/ExportTypes/ClassExport.cs b/Translation/UAssetAPI/ExportTypes/ClassExport.cs new file mode 100644 index 0000000..3ef27a9 --- /dev/null +++ b/Translation/UAssetAPI/ExportTypes/ClassExport.cs @@ -0,0 +1,217 @@ +using Newtonsoft.Json; +using System.IO; +using System.Linq; +using UAssetAPI.JSON; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI +{ + /// + /// Represents an interface that a UClass () implements. + /// + public struct SerializedInterfaceReference + { + public int Class; + public int PointerOffset; + public bool bImplementedByK2; + + public SerializedInterfaceReference(int @class, int pointerOffset, bool bImplementedByK2) + { + Class = @class; + PointerOffset = pointerOffset; + this.bImplementedByK2 = bImplementedByK2; + } + } + + /// + /// Represents an object class. + /// + public class ClassExport : StructExport + { + /// + /// Map of all functions by name contained in this class + /// + [JsonConverter(typeof(TMapJsonConverter))] + public TMap FuncMap; + + /// + /// Class flags; See for more information + /// + public EClassFlags ClassFlags; + + /// + /// The required type for the outer of instances of this class + /// + public FPackageIndex ClassWithin; + + /// + /// Which Name.ini file to load Config variables out of + /// + public FName ClassConfigName; + + /// + /// The list of interfaces which this class implements, along with the pointer property that is located at the offset of the interface's vtable. + /// If the interface class isn't native, the property will be empty. + /// + public SerializedInterfaceReference[] Interfaces; + + /// + /// This is the blueprint that caused the generation of this class, or null if it is a native compiled-in class + /// + public FPackageIndex ClassGeneratedBy; + + /// + /// Does this class use deprecated script order? + /// + public bool bDeprecatedForceScriptOrder; + + /// + /// Used to check if the class was cooked or not + /// + public bool bCooked; + + /// + /// The class default object; used for delta serialization and object initialization + /// + public FPackageIndex ClassDefaultObject; + + public ClassExport(Export super) : base(super) + { + + } + + public ClassExport(UAsset asset, byte[] extras) : base(asset, extras) + { + + } + + public ClassExport() + { + + } + + public override void Read(AssetBinaryReader reader, int nextStarting) + { + base.Read(reader, nextStarting); + + int numFuncIndexEntries = reader.ReadInt32(); + FuncMap = new TMap(); + for (int i = 0; i < numFuncIndexEntries; i++) + { + FName functionName = reader.ReadFName(); + FPackageIndex functionExport = FPackageIndex.FromRawIndex(reader.ReadInt32()); + + FuncMap.Add(functionName, functionExport); + } + + ClassFlags = (EClassFlags)reader.ReadUInt32(); + + if (Asset.EngineVersion < UE4Version.VER_UE4_CLASS_NOTPLACEABLE_ADDED) + { + ClassFlags ^= EClassFlags.CLASS_NotPlaceable; + } + + ClassWithin = new FPackageIndex(reader.ReadInt32()); + ClassConfigName = reader.ReadFName(); + Asset.AddNameReference(ClassConfigName.Value); + + int numInterfaces = 0; + long interfacesStart = 0; + if (Asset.EngineVersion < UE4Version.VER_UE4_UCLASS_SERIALIZE_INTERFACES_AFTER_LINKING) + { + interfacesStart = reader.BaseStream.Position; + numInterfaces = reader.ReadInt32(); + reader.BaseStream.Seek(interfacesStart + sizeof(int) + numInterfaces * (sizeof(int) * 3), SeekOrigin.Begin); + } + + // Linking procedure here; I don't think anything is really serialized during this + ClassGeneratedBy = new FPackageIndex(reader.ReadInt32()); + + long currentOffset = reader.BaseStream.Position; + if (Asset.EngineVersion < UE4Version.VER_UE4_UCLASS_SERIALIZE_INTERFACES_AFTER_LINKING) + { + reader.BaseStream.Seek(interfacesStart, SeekOrigin.Begin); + } + numInterfaces = reader.ReadInt32(); + Interfaces = new SerializedInterfaceReference[numInterfaces]; + for (int i = 0; i < numInterfaces; i++) + { + Interfaces[i] = new SerializedInterfaceReference(reader.ReadInt32(), reader.ReadInt32(), reader.ReadInt32() == 1); + } + if (Asset.EngineVersion < UE4Version.VER_UE4_UCLASS_SERIALIZE_INTERFACES_AFTER_LINKING) + { + reader.BaseStream.Seek(currentOffset, SeekOrigin.Begin); + } + + bDeprecatedForceScriptOrder = reader.ReadInt32() == 1; + + reader.ReadInt64(); // None + + if (Asset.EngineVersion >= UE4Version.VER_UE4_ADD_COOKED_TO_UCLASS) + { + bCooked = reader.ReadInt32() == 1; + } + + ClassDefaultObject = new FPackageIndex(reader.ReadInt32()); + + // CDO serialization usually comes after this export has finished serializing + } + + public override void Write(AssetBinaryWriter writer) + { + base.Write(writer); + + writer.Write(FuncMap.Count); + for (int i = 0; i < FuncMap.Count; i++) + { + writer.Write(FuncMap.Keys.ElementAt(i)); + writer.Write(FuncMap[i].Index); + } + + EClassFlags serializingClassFlags = ClassFlags; + if (Asset.EngineVersion < UE4Version.VER_UE4_CLASS_NOTPLACEABLE_ADDED) + { + serializingClassFlags ^= EClassFlags.CLASS_NotPlaceable; + } + writer.Write((uint)serializingClassFlags); + + writer.Write(ClassWithin.Index); + writer.Write(ClassConfigName); + + if (Asset.EngineVersion < UE4Version.VER_UE4_UCLASS_SERIALIZE_INTERFACES_AFTER_LINKING) + { + SerializeInterfaces(writer); + } + + // Linking procedure here; I don't think anything is really serialized during this + writer.Write(ClassGeneratedBy.Index); + + if (Asset.EngineVersion >= UE4Version.VER_UE4_UCLASS_SERIALIZE_INTERFACES_AFTER_LINKING) + { + SerializeInterfaces(writer); + } + + writer.Write(bDeprecatedForceScriptOrder ? 1 : 0); + + writer.Write(new FName(writer.Asset, "None")); + + if (Asset.EngineVersion >= UE4Version.VER_UE4_ADD_COOKED_TO_UCLASS) + { + writer.Write(bCooked ? 1 : 0); + } + + writer.Write(ClassDefaultObject.Index); + } + + private void SerializeInterfaces(BinaryWriter writer) + { + writer.Write(Interfaces.Length); + for (int i = 0; i < Interfaces.Length; i++) + { + writer.Write(Interfaces[i].Class); + writer.Write(Interfaces[i].PointerOffset); + writer.Write(Interfaces[i].bImplementedByK2 ? 1 : 0); + } + } + } +} diff --git a/Translation/UAssetAPI/ExportTypes/DataTableExport.cs b/Translation/UAssetAPI/ExportTypes/DataTableExport.cs new file mode 100644 index 0000000..db42f78 --- /dev/null +++ b/Translation/UAssetAPI/ExportTypes/DataTableExport.cs @@ -0,0 +1,108 @@ +using System; +using System.Collections.Generic; +using UAssetAPI.PropertyTypes.Objects; +using UAssetAPI.PropertyTypes.Structs; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI +{ + /// + /// Imported spreadsheet table. + /// + public class UDataTable + { + public List Data; + + public UDataTable() + { + Data = new List(); + } + + public UDataTable(List data) + { + Data = data; + } + } + + /// + /// Export for an imported spreadsheet table. See . + /// + public class DataTableExport : NormalExport + { + public UDataTable Table; + + public DataTableExport(Export super) : base(super) + { + + } + + public DataTableExport(UDataTable data, UAsset asset, byte[] extras) : base(asset, extras) + { + Table = data; + } + + public DataTableExport() + { + + } + + public override void Read(AssetBinaryReader reader, int nextStarting) + { + base.Read(reader, nextStarting); + + // Find an ObjectProperty named RowStruct + FName decidedStructType = FName.DefineDummy(reader.Asset, "Generic"); + foreach (PropertyData thisData in Data) + { + if (thisData.Name.Value.Value == "RowStruct" && thisData is ObjectPropertyData thisObjData && thisObjData.Value.IsImport()) + { + decidedStructType = thisObjData.ToImport(reader.Asset).ObjectName; + break; + } + } + + reader.ReadInt32(); + + Table = new UDataTable(); + + int numEntries = reader.ReadInt32(); + for (int i = 0; i < numEntries; i++) + { + FName rowName = reader.ReadFName(); + var nextStruct = new StructPropertyData(rowName) + { + StructType = decidedStructType + }; + nextStruct.Read(reader, false, 1); + Table.Data.Add(nextStruct); + } + } + + public override void Write(AssetBinaryWriter writer) + { + base.Write(writer); + + // Find an ObjectProperty named RowStruct + FName decidedStructType = FName.DefineDummy(writer.Asset, "Generic"); + foreach (PropertyData thisData in Data) + { + if (thisData.Name.Value.Value == "RowStruct" && thisData is ObjectPropertyData thisObjData) + { + decidedStructType = thisObjData.ToImport(writer.Asset).ObjectName; + break; + } + } + + writer.Write((int)0); + + writer.Write(Table.Data.Count); + for (int i = 0; i < Table.Data.Count; i++) + { + var thisDataTableEntry = Table.Data[i]; + thisDataTableEntry.StructType = decidedStructType; + writer.Write(thisDataTableEntry.Name); + thisDataTableEntry.Write(writer, false); + } + } + } +} diff --git a/Translation/UAssetAPI/ExportTypes/EnumExport.cs b/Translation/UAssetAPI/ExportTypes/EnumExport.cs new file mode 100644 index 0000000..4b8196b --- /dev/null +++ b/Translation/UAssetAPI/ExportTypes/EnumExport.cs @@ -0,0 +1,155 @@ +using System; +using System.Collections.Generic; +using System.IO; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI +{ + /// How this enum is declared in C++. Affects the internal naming of enum values. + public enum ECppForm + { + Regular, + Namespaced, + EnumClass + } + + /// + /// Reflection data for an enumeration. + /// + public class UEnum + { + /// List of pairs of all enum names and values. + public List> Names; + + /// How the enum was originally defined. + public ECppForm CppForm = ECppForm.Regular; + + public void Read(AssetBinaryReader reader, UAsset asset) + { + if (asset.EngineVersion < UE4Version.VER_UE4_TIGHTLY_PACKED_ENUMS) + { + int numEntries = reader.ReadInt32(); + for (int i = 0; i < numEntries; i++) + { + FName tempName = reader.ReadFName(); + Names.Add(new Tuple(tempName, i)); + } + } + else if (asset.GetCustomVersion() < FCoreObjectVersion.EnumProperties) + { + int numEntries = reader.ReadInt32(); + for (int i = 0; i < numEntries; i++) + { + FName tempName = reader.ReadFName(); + byte tempVal = reader.ReadByte(); + Names.Add(new Tuple(tempName, tempVal)); + } + } + else + { + int numEntries = reader.ReadInt32(); + for (int i = 0; i < numEntries; i++) + { + FName tempName = reader.ReadFName(); + long tempVal = reader.ReadInt64(); + Names.Add(new Tuple(tempName, tempVal)); + } + } + + if (asset.EngineVersion < UE4Version.VER_UE4_ENUM_CLASS_SUPPORT) + { + bool bIsNamespace = reader.ReadInt32() == 1; + CppForm = bIsNamespace ? ECppForm.Namespaced : ECppForm.Regular; + } + else + { + CppForm = (ECppForm)reader.ReadByte(); + } + } + + public void Write(AssetBinaryWriter writer, UAsset asset) + { + writer.Write(Names.Count); + if (asset.EngineVersion < UE4Version.VER_UE4_TIGHTLY_PACKED_ENUMS) + { + var namesForSerialization = new Dictionary(); + for (int i = 0; i < Names.Count; i++) namesForSerialization.Add(Names[i].Item2, Names[i].Item1); + for (int i = 0; i < Names.Count; i++) + { + if (namesForSerialization.ContainsKey(i)) writer.Write(namesForSerialization[i]); + } + } + else if (asset.GetCustomVersion() < FCoreObjectVersion.EnumProperties) + { + for (int i = 0; i < Names.Count; i++) + { + writer.Write(Names[i].Item1); + writer.Write((byte)Names[i].Item2); + } + } + else + { + for (int i = 0; i < Names.Count; i++) + { + writer.Write(Names[i].Item1); + writer.Write(Names[i].Item2); + } + } + + if (asset.EngineVersion < UE4Version.VER_UE4_ENUM_CLASS_SUPPORT) + { + writer.Write(CppForm == ECppForm.Namespaced ? 1 : 0); + } + else + { + writer.Write((byte)CppForm); + } + } + + public UEnum() + { + Names = new List>(); + } + } + + /// + /// Export data for an enumeration. See . + /// + public class EnumExport : NormalExport + { + /// The enum that is stored in this export. + public UEnum Enum; + + public EnumExport(Export super) : base(super) + { + + } + + public EnumExport(UAsset asset, byte[] extras) : base(asset, extras) + { + + } + + public EnumExport() + { + + } + + public override void Read(AssetBinaryReader reader, int nextStarting) + { + base.Read(reader, nextStarting); + reader.ReadInt32(); + + Enum = new UEnum(); + Enum.Read(reader, Asset); + } + + public override void Write(AssetBinaryWriter writer) + { + base.Write(writer); + writer.Write((int)0); + + Enum.Write(writer, Asset); + } + } +} diff --git a/Translation/UAssetAPI/ExportTypes/Export.cs b/Translation/UAssetAPI/ExportTypes/Export.cs new file mode 100644 index 0000000..08183d7 --- /dev/null +++ b/Translation/UAssetAPI/ExportTypes/Export.cs @@ -0,0 +1,199 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Text; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI +{ + [AttributeUsage(AttributeTargets.Field)] + internal class DisplayIndexOrderAttribute : Attribute + { + internal int DisplayingIndex = 0; + internal DisplayIndexOrderAttribute(int displayingIndex) + { + DisplayingIndex = displayingIndex; + } + } + + /// + /// UObject resource type for objects that are contained within this package and can be referenced by other packages. + /// + [JsonObject(MemberSerialization.OptOut)] + public class Export : FObjectResource, ICloneable + { + ///Location of this export's class (import/other export). 0 = this export is a UClass + [DisplayIndexOrder(2)] + public FPackageIndex ClassIndex; + ///Location of this export's parent class (import/other export). 0 = this export is not derived from UStruct + [DisplayIndexOrder(3)] + public FPackageIndex SuperIndex; + ///Location of this export's template (import/other export). 0 = there is some problem + [DisplayIndexOrder(4)] + public FPackageIndex TemplateIndex; + ///The object flags for the UObject represented by this resource. Only flags that match the RF_Load combination mask will be loaded from disk and applied to the UObject. + [DisplayIndexOrder(5)] + public EObjectFlags ObjectFlags; + ///The number of bytes to serialize when saving/loading this export's UObject. + [DisplayIndexOrder(6)] + public long SerialSize; + ///The location (into the FLinker's underlying file reader archive) of the beginning of the data for this export's UObject. Used for verification only. + [DisplayIndexOrder(7)] + public long SerialOffset; + ///Was this export forced into the export table via OBJECTMARK_ForceTagExp? + [DisplayIndexOrder(8)] + public bool bForcedExport; + ///Should this export not be loaded on clients? + [DisplayIndexOrder(9)] + public bool bNotForClient; + ///Should this export not be loaded on servers? + [DisplayIndexOrder(10)] + public bool bNotForServer; + ///If this object is a top level package (which must have been forced into the export table via OBJECTMARK_ForceTagExp), this is the GUID for the original package file. Deprecated + [DisplayIndexOrder(11)] + public Guid PackageGuid; + ///If this export is a top-level package, this is the flags for the original package + [DisplayIndexOrder(12)] + public EPackageFlags PackageFlags; + ///Should this export be always loaded in editor game? + [DisplayIndexOrder(13)] + public bool bNotAlwaysLoadedForEditorGame; + ///Is this export an asset? + [DisplayIndexOrder(14)] + public bool bIsAsset; + + /// + /// The export table must serialize as a fixed size, this is used to index into a long list, which is later loaded into the array. -1 means dependencies are not present. These are contiguous blocks, so CreateBeforeSerializationDependencies starts at FirstExportDependency + SerializationBeforeSerializationDependencies. + /// + internal int FirstExportDependencyOffset; + internal int SerializationBeforeSerializationDependenciesSize; + internal int CreateBeforeSerializationDependenciesSize; + internal int SerializationBeforeCreateDependenciesSize; + internal int CreateBeforeCreateDependenciesSize; + + [DisplayIndexOrder(15)] + public List SerializationBeforeSerializationDependencies = new List(); + [DisplayIndexOrder(16)] + public List CreateBeforeSerializationDependencies = new List(); + [DisplayIndexOrder(17)] + public List SerializationBeforeCreateDependencies = new List(); + [DisplayIndexOrder(18)] + public List CreateBeforeCreateDependencies = new List(); + + /// + /// Miscellaneous, unparsed export data, stored as a byte array. + /// + public byte[] Extras; + + /// + /// The asset that this export is parsed with. + /// + [JsonIgnore] + public UAsset Asset; + + public Export(UAsset asset, byte[] extras) + { + Asset = asset; + Extras = extras; + } + + public Export() + { + + } + + public virtual void Read(AssetBinaryReader reader, int nextStarting = 0) + { + + } + + public virtual void Write(AssetBinaryWriter writer) + { + + } + + private static FieldInfo[] _allFields = null; + private static void InitAllFields() + { + if (_allFields != null) return; + _allFields = UAPUtils.GetOrderedFields(); + } + + public static FieldInfo[] GetAllObjectExportFields() + { + InitAllFields(); + + return _allFields; + } + + public static string[] GetAllFieldNames() + { + InitAllFields(); + + string[] allFieldNames = new string[_allFields.Length]; + for (int i = 0; i < _allFields.Length; i++) + { + allFieldNames[i] = _allFields[i].Name; + } + return allFieldNames; + } + + public FName GetExportClassType() + { + return this.ClassIndex.IsImport() ? this.ClassIndex.ToImport(Asset).ObjectName : FName.DefineDummy(Asset, this.ClassIndex.Index.ToString()); + } + + public override string ToString() + { + InitAllFields(); + + var sb = new StringBuilder(); + foreach (var info in _allFields) + { + var value = info.GetValue(this) ?? "(null)"; + sb.AppendLine(info.Name + ": " + value.ToString()); + } + return sb.ToString(); + } + + public object Clone() + { + var res = (Export)MemberwiseClone(); + res.SerializationBeforeSerializationDependencies = this.SerializationBeforeSerializationDependencies.ToList(); + res.CreateBeforeSerializationDependencies = this.CreateBeforeSerializationDependencies.ToList(); + res.SerializationBeforeCreateDependencies = this.SerializationBeforeCreateDependencies.ToList(); + res.CreateBeforeCreateDependencies = this.CreateBeforeCreateDependencies.ToList(); + res.Extras = (byte[])this.Extras.Clone(); + res.PackageGuid = new Guid(this.PackageGuid.ToByteArray()); + return res; + } + + /// + /// Creates a child export instance with the same export details as the current export. + /// + /// The type of child export to create. + /// An instance of the child export type provided with the export details copied over. + public T ConvertToChildExport() where T : Export, new() + { + InitAllFields(); + + Export res = new T(); + res.SerializationBeforeSerializationDependencies = this.SerializationBeforeSerializationDependencies.ToList(); + res.CreateBeforeSerializationDependencies = this.CreateBeforeSerializationDependencies.ToList(); + res.SerializationBeforeCreateDependencies = this.SerializationBeforeCreateDependencies.ToList(); + res.CreateBeforeCreateDependencies = this.CreateBeforeCreateDependencies.ToList(); + res.Asset = this.Asset; + res.Extras = this.Extras; + res.ObjectName = this.ObjectName; + res.OuterIndex = this.OuterIndex; + foreach (var info in _allFields) + { + info.SetValue(res, info.GetValue(this)); + } + return (T)res; + } + } +} diff --git a/Translation/UAssetAPI/ExportTypes/FieldExport.cs b/Translation/UAssetAPI/ExportTypes/FieldExport.cs new file mode 100644 index 0000000..efa4a43 --- /dev/null +++ b/Translation/UAssetAPI/ExportTypes/FieldExport.cs @@ -0,0 +1,46 @@ +using System.Linq; +using UAssetAPI.FieldTypes; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI +{ + /// + /// Export data for a . + /// + public class FieldExport : NormalExport + { + public UField Field; + + public FieldExport(Export super) : base(super) + { + + } + + public FieldExport(UAsset asset, byte[] extras) : base(asset, extras) + { + + } + + public FieldExport() + { + + } + + public override void Read(AssetBinaryReader reader, int nextStarting) + { + base.Read(reader, nextStarting); + reader.ReadInt32(); + + Field = new UField(); + Field.Read(reader); + } + + public override void Write(AssetBinaryWriter writer) + { + base.Write(writer); + writer.Write((int)0); + + Field.Write(writer); + } + } +} diff --git a/Translation/UAssetAPI/ExportTypes/FunctionExport.cs b/Translation/UAssetAPI/ExportTypes/FunctionExport.cs new file mode 100644 index 0000000..31e1f6d --- /dev/null +++ b/Translation/UAssetAPI/ExportTypes/FunctionExport.cs @@ -0,0 +1,42 @@ +using System.IO; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI +{ + /// + /// Export data for a blueprint function. + /// + public class FunctionExport : StructExport + { + public EFunctionFlags FunctionFlags; + public FunctionExport(Export super) : base(super) + { + Asset = super.Asset; + Extras = super.Extras; + } + + public FunctionExport(UAsset asset, byte[] extras) : base(asset, extras) + { + + } + + public FunctionExport() + { + + } + + public override void Read(AssetBinaryReader reader, int nextStarting) + { + base.Read(reader, nextStarting); + FunctionFlags = (EFunctionFlags)reader.ReadUInt32(); + // TODO + } + + public override void Write(AssetBinaryWriter writer) + { + base.Write(writer); + writer.Write((uint)FunctionFlags); + // TODO + } + } +} diff --git a/Translation/UAssetAPI/ExportTypes/LevelExport.cs b/Translation/UAssetAPI/ExportTypes/LevelExport.cs new file mode 100644 index 0000000..c383433 --- /dev/null +++ b/Translation/UAssetAPI/ExportTypes/LevelExport.cs @@ -0,0 +1,101 @@ +using System.Collections.Generic; +using System.IO; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI +{ + public class NamespacedString + { + public FString Namespace; + public FString Value; + + public NamespacedString(FString Namespace, FString Value) + { + this.Namespace = Namespace; + this.Value = Value; + } + + public NamespacedString() + { + + } + } + + public class LevelExport : NormalExport + { + public List IndexData; + public NamespacedString LevelType; + public ulong FlagsProbably; + public List MiscCategoryData; + + public LevelExport(Export super) : base(super) + { + + } + + public LevelExport(UAsset asset, byte[] extras) : base(asset, extras) + { + + } + + public LevelExport() + { + + } + public override void Read(AssetBinaryReader reader, int nextStarting) + { + base.Read(reader, nextStarting); + + reader.ReadInt32(); + int numIndexEntries = reader.ReadInt32(); + + IndexData = new List(); + for (int i = 0; i < numIndexEntries; i++) + { + IndexData.Add(reader.ReadInt32()); + } + + var nms = reader.ReadFString(); + reader.ReadInt32(); // null + var val = reader.ReadFString(); + LevelType = new NamespacedString(nms, val); + + reader.ReadInt64(); // null + FlagsProbably = reader.ReadUInt64(); + + MiscCategoryData = new List(); + while (reader.BaseStream.Position < nextStarting - 1) + { + MiscCategoryData.Add(reader.ReadInt32()); + } + + reader.ReadByte(); + } + + public override void Write(AssetBinaryWriter writer) + { + base.Write(writer); + + writer.Write((int)0); + writer.Write(IndexData.Count); + for (int i = 0; i < IndexData.Count; i++) + { + writer.Write(IndexData[i]); + } + + writer.Write(LevelType.Namespace); + writer.Write((int)0); + writer.Write(LevelType.Value); + + writer.Write((long)0); + writer.Write(FlagsProbably); + + for (int i = 0; i < MiscCategoryData.Count; i++) + { + writer.Write(MiscCategoryData[i]); + } + + writer.Write((byte)0); + } + } +} diff --git a/Translation/UAssetAPI/ExportTypes/NormalExport.cs b/Translation/UAssetAPI/ExportTypes/NormalExport.cs new file mode 100644 index 0000000..60f7043 --- /dev/null +++ b/Translation/UAssetAPI/ExportTypes/NormalExport.cs @@ -0,0 +1,116 @@ +using System.Collections.Generic; +using UAssetAPI.PropertyTypes.Objects; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI +{ + /// + /// A regular export, with no special serialization. Serialized as a None-terminated property list. + /// + public class NormalExport : Export + { + public List Data; + + /// + /// Gets or sets the value associated with the specified key. This operation loops linearly, so it may not be suitable for high-performance environments. + /// + /// The key associated with the value to get or set. + public PropertyData this[FName key] + { + get + { + for (int i = 0; i < Data.Count; i++) + { + if (Data[i].Name == key) return Data[i]; + } + return null; + } + set + { + for (int i = 0; i < Data.Count; i++) + { + if (Data[i].Name == key) + { + Data[i] = value; + Data[i].Name = key; + break; + } + } + } + } + + /// + /// Gets or sets the value associated with the specified key. This operation loops linearly, so it may not be suitable for high-performance environments. + /// + /// The key associated with the value to get or set. + public PropertyData this[string key] + { + get + { + return this[FName.FromString(Asset, key)]; + } + set + { + this[FName.FromString(Asset, key)] = value; + } + } + + + /// + /// Gets or sets the value at the specified index. + /// + /// The index of the value to get or set. + public PropertyData this[int index] + { + get + { + return Data[index]; + } + set + { + Data[index] = value; + } + } + + public NormalExport(Export super) + { + Asset = super.Asset; + Extras = super.Extras; + } + + public NormalExport(UAsset asset, byte[] extras) : base(asset, extras) + { + + } + + public NormalExport(List data, UAsset asset, byte[] extras) : base(asset, extras) + { + Data = data; + } + + public NormalExport() + { + + } + + public override void Read(AssetBinaryReader reader, int nextStarting = 0) + { + Data = new List(); + PropertyData bit; + while ((bit = MainSerializer.Read(reader, true)) != null) + { + Data.Add(bit); + } + } + + public override void Write(AssetBinaryWriter writer) + { + for (int j = 0; j < Data.Count; j++) + { + PropertyData current = Data[j]; + MainSerializer.Write(current, writer, true); + } + writer.Write(new FName(writer.Asset, "None")); + } + } +} diff --git a/Translation/UAssetAPI/ExportTypes/PropertyExport.cs b/Translation/UAssetAPI/ExportTypes/PropertyExport.cs new file mode 100644 index 0000000..2c7c9b1 --- /dev/null +++ b/Translation/UAssetAPI/ExportTypes/PropertyExport.cs @@ -0,0 +1,46 @@ +using System.Linq; +using UAssetAPI.FieldTypes; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI +{ + /// + /// Export data for a . + /// + public class PropertyExport : NormalExport + { + public UProperty Property; + + public PropertyExport(Export super) : base(super) + { + + } + + public PropertyExport(UAsset asset, byte[] extras) : base(asset, extras) + { + + } + + public PropertyExport() + { + + } + + public override void Read(AssetBinaryReader reader, int nextStarting) + { + base.Read(reader, nextStarting); + reader.ReadInt32(); + + FName exportClassType = this.GetExportClassType(); + Property = MainSerializer.ReadUProperty(reader, exportClassType); + } + + public override void Write(AssetBinaryWriter writer) + { + base.Write(writer); + writer.Write((int)0); + + MainSerializer.WriteUProperty(Property, writer); + } + } +} diff --git a/Translation/UAssetAPI/ExportTypes/RawExport.cs b/Translation/UAssetAPI/ExportTypes/RawExport.cs new file mode 100644 index 0000000..586cfa5 --- /dev/null +++ b/Translation/UAssetAPI/ExportTypes/RawExport.cs @@ -0,0 +1,34 @@ +using System.IO; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI +{ + /// + /// An export that could not be properly parsed by UAssetAPI, and is instead represented as an array of bytes as a fallback. + /// + public class RawExport : Export + { + public byte[] Data; + + public RawExport(Export super) + { + Asset = super.Asset; + Extras = super.Extras; + } + + public RawExport(byte[] data, UAsset asset, byte[] extras) : base(asset, extras) + { + Data = data; + } + + public RawExport() + { + + } + + public override void Write(AssetBinaryWriter writer) + { + writer.Write(Data); + } + } +} diff --git a/Translation/UAssetAPI/ExportTypes/StringTableExport.cs b/Translation/UAssetAPI/ExportTypes/StringTableExport.cs new file mode 100644 index 0000000..fbbd0c7 --- /dev/null +++ b/Translation/UAssetAPI/ExportTypes/StringTableExport.cs @@ -0,0 +1,77 @@ +using Newtonsoft.Json; +using System.Linq; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI +{ + /// + /// A string table. Holds Key->SourceString pairs of text. + /// + public class FStringTable : TMap + { + [JsonProperty] + public FString TableNamespace; + + public FStringTable(FString tableNamespace) : base() + { + TableNamespace = tableNamespace; + } + + public FStringTable() : base() + { + + } + } + + /// + /// Export data for a string table. See . + /// + public class StringTableExport : NormalExport + { + [JsonProperty] + public FStringTable Table; + + public StringTableExport(Export super) : base(super) + { + + } + + public StringTableExport(FStringTable data, UAsset asset, byte[] extras) : base(asset, extras) + { + Table = data; + } + + public StringTableExport() + { + + } + + public override void Read(AssetBinaryReader reader, int nextStarting) + { + base.Read(reader, nextStarting); + reader.ReadInt32(); + + Table = new FStringTable(reader.ReadFString()); + + int numEntries = reader.ReadInt32(); + for (int i = 0; i < numEntries; i++) + { + Table.Add(reader.ReadFString(), reader.ReadFString()); + } + } + + public override void Write(AssetBinaryWriter writer) + { + base.Write(writer); + writer.Write((int)0); + + writer.Write(Table.TableNamespace); + writer.Write(Table.Count); + for (int i = 0; i < Table.Count; i++) + { + writer.Write(Table.Keys.ElementAt(i)); + writer.Write(Table[i]); + } + } + } +} diff --git a/Translation/UAssetAPI/ExportTypes/StructExport.cs b/Translation/UAssetAPI/ExportTypes/StructExport.cs new file mode 100644 index 0000000..72e6384 --- /dev/null +++ b/Translation/UAssetAPI/ExportTypes/StructExport.cs @@ -0,0 +1,179 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using UAssetAPI.FieldTypes; +using UAssetAPI.Kismet.Bytecode; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI +{ + /// + /// Base export for all UObject types that contain fields. + /// + public class StructExport : FieldExport + { + /// + /// Struct this inherits from, may be null + /// + public FPackageIndex SuperStruct; + + /// + /// List of child fields + /// + public FPackageIndex[] Children; + + /// + /// Properties serialized with this struct definition + /// + public FProperty[] LoadedProperties; + + /// + /// The bytecode instructions contained within this struct. + /// + public KismetExpression[] ScriptBytecode; + + /// + /// Bytecode size in total in deserialized memory. Filled out in lieu of if an error occurs during bytecode parsing. + /// + public int ScriptBytecodeSize; + + /// + /// Raw binary bytecode data. Filled out in lieu of if an error occurs during bytecode parsing. + /// + public byte[] ScriptBytecodeRaw; + + /// + /// A static bool that determines whether or not the serializer will attempt to parse Kismet bytecode. + /// + private static readonly bool ParseBytecode = true; + + public StructExport(Export super) : base(super) + { + + } + + public StructExport(UAsset asset, byte[] extras) : base(asset, extras) + { + + } + + public StructExport() + { + + } + + public override void Read(AssetBinaryReader reader, int nextStarting) + { + base.Read(reader, nextStarting); + + SuperStruct = new FPackageIndex(reader.ReadInt32()); + + int numIndexEntries = reader.ReadInt32(); + Children = new FPackageIndex[numIndexEntries]; + for (int i = 0; i < numIndexEntries; i++) + { + Children[i] = new FPackageIndex(reader.ReadInt32()); + } + + if (Asset.GetCustomVersion() >= FCoreObjectVersion.FProperties) + { + int numProps = reader.ReadInt32(); + LoadedProperties = new FProperty[numProps]; + for (int i = 0; i < numProps; i++) + { + LoadedProperties[i] = MainSerializer.ReadFProperty(reader); + } + } + else + { + LoadedProperties = new FProperty[0]; + } + + ScriptBytecodeSize = reader.ReadInt32(); // # of bytes in total in deserialized memory + int scriptStorageSize = reader.ReadInt32(); // # of bytes in total + long startedReading = reader.BaseStream.Position; + + bool willParseRaw = true; + try + { + if (ParseBytecode && Asset.EngineVersion >= UE4Version.VER_UE4_16) + { + var tempCode = new List(); + while ((reader.BaseStream.Position - startedReading) < scriptStorageSize) + { + tempCode.Add(ExpressionSerializer.ReadExpression(reader)); + } + ScriptBytecode = tempCode.ToArray(); + willParseRaw = false; + } + } + catch (Exception ex) + { +#if DEBUG + Debug.WriteLine(ex.StackTrace); +#endif + } + + if (willParseRaw) + { + reader.BaseStream.Seek(startedReading, SeekOrigin.Begin); + ScriptBytecode = null; + ScriptBytecodeRaw = reader.ReadBytes(scriptStorageSize); + } + } + + public override void Write(AssetBinaryWriter writer) + { + base.Write(writer); + + writer.Write(SuperStruct.Index); + + writer.Write(Children.Length); + for (int i = 0; i < Children.Length; i++) + { + writer.Write(Children[i].Index); + } + + if (Asset.GetCustomVersion() >= FCoreObjectVersion.FProperties) + { + writer.Write(LoadedProperties.Length); + for (int i = 0; i < LoadedProperties.Length; i++) + { + MainSerializer.WriteFProperty(LoadedProperties[i], writer); + } + } + + if (ScriptBytecode == null) + { + writer.Write(ScriptBytecodeSize); + writer.Write(ScriptBytecodeRaw.Length); + writer.Write(ScriptBytecodeRaw); + } + else + { + long lengthOffset1 = writer.BaseStream.Position; + writer.Write((int)0); // total iCode offset; to be filled out after serialization + long lengthOffset2 = writer.BaseStream.Position; + writer.Write((int)0); // size on disk; to be filled out after serialization + + int totalICodeOffset = 0; + long startMetric = writer.BaseStream.Position; + for (int i = 0; i < ScriptBytecode.Length; i++) + { + totalICodeOffset += ExpressionSerializer.WriteExpression(ScriptBytecode[i], writer); + } + long endMetric = writer.BaseStream.Position; + + // Write out total size in bytes + long totalLength = endMetric - startMetric; + long here = writer.BaseStream.Position; + writer.Seek((int)lengthOffset1, SeekOrigin.Begin); + writer.Write(totalICodeOffset); + writer.Seek((int)lengthOffset2, SeekOrigin.Begin); + writer.Write((int)totalLength); + writer.Seek((int)here, SeekOrigin.Begin); + } + } + } +} diff --git a/Translation/UAssetAPI/FieldTypes/EArrayDim.cs b/Translation/UAssetAPI/FieldTypes/EArrayDim.cs new file mode 100644 index 0000000..73881a1 --- /dev/null +++ b/Translation/UAssetAPI/FieldTypes/EArrayDim.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.FieldTypes +{ + /// + /// The type of array that this property represents. This is represented an integer in the engine. + /// + public enum EArrayDim : int + { + NotAnArray = 0, + TArray = 1, + CArray = 2 + } +} diff --git a/Translation/UAssetAPI/FieldTypes/ELifetimeCondition.cs b/Translation/UAssetAPI/FieldTypes/ELifetimeCondition.cs new file mode 100644 index 0000000..b427489 --- /dev/null +++ b/Translation/UAssetAPI/FieldTypes/ELifetimeCondition.cs @@ -0,0 +1,45 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.FieldTypes +{ + /// Secondary condition to check before considering the replication of a lifetime property. + public enum ELifetimeCondition : byte + { + /// This property has no condition, and will send anytime it changes + COND_None = 0, + /// This property will only attempt to send on the initial bunch + COND_InitialOnly = 1, + /// This property will only send to the actor's owner + COND_OwnerOnly = 2, + /// This property send to every connection EXCEPT the owner + COND_SkipOwner = 3, + /// This property will only send to simulated actors + COND_SimulatedOnly = 4, + /// This property will only send to autonomous actors + COND_AutonomousOnly = 5, + /// This property will send to simulated OR bRepPhysics actors + COND_SimulatedOrPhysics = 6, + /// This property will send on the initial packet, or to the actors owner + COND_InitialOrOwner = 7, + /// This property has no particular condition, but wants the ability to toggle on/off via SetCustomIsActiveOverride + COND_Custom = 8, + /// This property will only send to the replay connection, or to the actors owner + COND_ReplayOrOwner = 9, + /// This property will only send to the replay connection + COND_ReplayOnly = 10, + /// This property will send to actors only, but not to replay connections + COND_SimulatedOnlyNoReplay = 11, + /// This property will send to simulated Or bRepPhysics actors, but not to replay connections + COND_SimulatedOrPhysicsNoReplay = 12, + /// This property will not send to the replay connection + COND_SkipReplay = 13, + /// This property will never be replicated + COND_Never = 15, + COND_Max = 16 + }; +} diff --git a/Translation/UAssetAPI/FieldTypes/FField.cs b/Translation/UAssetAPI/FieldTypes/FField.cs new file mode 100644 index 0000000..92c2508 --- /dev/null +++ b/Translation/UAssetAPI/FieldTypes/FField.cs @@ -0,0 +1,371 @@ +using System.IO; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.FieldTypes +{ + /// + /// Base class of reflection data objects. + /// + public class FField + { + public FName SerializedType; + public FName Name; + public EObjectFlags Flags; + + public virtual void Read(AssetBinaryReader reader) + { + Name = reader.ReadFName(); + Flags = (EObjectFlags)reader.ReadUInt32(); + } + + public virtual void Write(AssetBinaryWriter writer) + { + writer.Write(Name); + writer.Write((uint)Flags); + } + + public FField() + { + + } + } + + /// + /// An UnrealScript variable. + /// + public abstract class FProperty : FField + { + public EArrayDim ArrayDim; + public int ElementSize; + public EPropertyFlags PropertyFlags; + public ushort RepIndex; + public FName RepNotifyFunc; + public ELifetimeCondition BlueprintReplicationCondition; + + public object RawValue; + + public void SetObject(object value) + { + RawValue = value; + } + + public T GetObject() + { + return (T)RawValue; + } + + public override void Read(AssetBinaryReader reader) + { + base.Read(reader); + ArrayDim = (EArrayDim)reader.ReadInt32(); + ElementSize = reader.ReadInt32(); + PropertyFlags = (EPropertyFlags)reader.ReadUInt64(); + RepIndex = reader.ReadUInt16(); + RepNotifyFunc = reader.ReadFName(); + BlueprintReplicationCondition = (ELifetimeCondition)reader.ReadByte(); + } + + public override void Write(AssetBinaryWriter writer) + { + base.Write(writer); + writer.Write((int)ArrayDim); + writer.Write(ElementSize); + writer.Write((ulong)PropertyFlags); + writer.Write(RepIndex); + writer.Write(RepNotifyFunc); + writer.Write((byte)BlueprintReplicationCondition); + } + + public FProperty() + { + + } + } + + public class FEnumProperty : FProperty + { + ///A pointer to the UEnum represented by this property + public FPackageIndex Enum; + ///The FNumericProperty which represents the underlying type of the enum + public FProperty UnderlyingProp; + + public override void Read(AssetBinaryReader reader) + { + base.Read(reader); + + Enum = new FPackageIndex(reader.ReadInt32()); + UnderlyingProp = MainSerializer.ReadFProperty(reader); + } + + public override void Write(AssetBinaryWriter writer) + { + base.Write(writer); + + writer.Write(Enum.Index); + MainSerializer.WriteFProperty(UnderlyingProp, writer); + } + } + + public class FArrayProperty : FProperty + { + public FProperty Inner; + + public override void Read(AssetBinaryReader reader) + { + base.Read(reader); + Inner = MainSerializer.ReadFProperty(reader); + } + + public override void Write(AssetBinaryWriter writer) + { + base.Write(writer); + MainSerializer.WriteFProperty(Inner, writer); + } + } + + public class FSetProperty : FProperty + { + public FProperty ElementProp; + + public override void Read(AssetBinaryReader reader) + { + base.Read(reader); + ElementProp = MainSerializer.ReadFProperty(reader); + } + + public override void Write(AssetBinaryWriter writer) + { + base.Write(writer); + MainSerializer.WriteFProperty(ElementProp, writer); + } + } + + public class FObjectProperty : FProperty + { + // UClass* + public FPackageIndex PropertyClass; + + public override void Read(AssetBinaryReader reader) + { + base.Read(reader); + PropertyClass = new FPackageIndex(reader.ReadInt32()); + } + + public override void Write(AssetBinaryWriter writer) + { + base.Write(writer); + writer.Write(PropertyClass.Index); + } + } + + public class FSoftObjectProperty : FObjectProperty + { + + } + + public class FClassProperty : FObjectProperty + { + // UClass* + public FPackageIndex MetaClass; + + public override void Read(AssetBinaryReader reader) + { + base.Read(reader); + MetaClass = new FPackageIndex(reader.ReadInt32()); + } + + public override void Write(AssetBinaryWriter writer) + { + base.Write(writer); + writer.Write(MetaClass.Index); + } + } + + public class FSoftClassProperty : FObjectProperty + { + // UClass* + public FPackageIndex MetaClass; + + public override void Read(AssetBinaryReader reader) + { + base.Read(reader); + MetaClass = new FPackageIndex(reader.ReadInt32()); + } + + public override void Write(AssetBinaryWriter writer) + { + base.Write(writer); + writer.Write(MetaClass.Index); + } + } + + public class FDelegateProperty : FProperty + { + // UFunction* + public FPackageIndex SignatureFunction; + + public override void Read(AssetBinaryReader reader) + { + base.Read(reader); + SignatureFunction = new FPackageIndex(reader.ReadInt32()); + } + + public override void Write(AssetBinaryWriter writer) + { + base.Write(writer); + writer.Write(SignatureFunction.Index); + } + } + + public class FMulticastDelegateProperty : FDelegateProperty + { + + } + + public class FMulticastInlineDelegateProperty : FMulticastDelegateProperty + { + + } + + public class FInterfaceProperty : FProperty + { + // UFunction* + public FPackageIndex InterfaceClass; + + public override void Read(AssetBinaryReader reader) + { + base.Read(reader); + InterfaceClass = new FPackageIndex(reader.ReadInt32()); + } + + public override void Write(AssetBinaryWriter writer) + { + base.Write(writer); + writer.Write(InterfaceClass.Index); + } + } + + public class FMapProperty : FProperty + { + public FProperty KeyProp; + public FProperty ValueProp; + + public override void Read(AssetBinaryReader reader) + { + base.Read(reader); + KeyProp = MainSerializer.ReadFProperty(reader); + ValueProp = MainSerializer.ReadFProperty(reader); + } + + public override void Write(AssetBinaryWriter writer) + { + base.Write(writer); + MainSerializer.WriteFProperty(KeyProp, writer); + MainSerializer.WriteFProperty(ValueProp, writer); + } + } + + public class FBoolProperty : FProperty + { + /// Size of the bitfield/bool property. Equal to ElementSize but used to check if the property has been properly initialized (0-8, where 0 means uninitialized). + public byte FieldSize; + /// Offset from the memeber variable to the byte of the property (0-7). + public byte ByteOffset; + /// Mask of the byte with the property value. + public byte ByteMask; + /// Mask of the field with the property value. Either equal to ByteMask or 255 in case of 'bool' type. + public byte FieldMask; + + public bool NativeBool; + public bool Value; + + public override void Read(AssetBinaryReader reader) + { + base.Read(reader); + + byte BoolSize = (byte)ElementSize; + FieldSize = reader.ReadByte(); + ByteOffset = reader.ReadByte(); + ByteMask = reader.ReadByte(); + FieldMask = reader.ReadByte(); + NativeBool = reader.ReadBoolean(); + Value = reader.ReadBoolean(); + } + + public override void Write(AssetBinaryWriter writer) + { + base.Write(writer); + writer.Write(FieldSize); + writer.Write(ByteOffset); + writer.Write(ByteMask); + writer.Write(FieldMask); + writer.Write(NativeBool); + writer.Write(Value); + } + } + + public class FByteProperty : FProperty + { + /// A pointer to the UEnum represented by this property + public FPackageIndex Enum; + + public override void Read(AssetBinaryReader reader) + { + base.Read(reader); + Enum = new FPackageIndex(reader.ReadInt32()); + } + + public override void Write(AssetBinaryWriter writer) + { + base.Write(writer); + writer.Write(Enum.Index); + } + } + + public class FStructProperty : FProperty + { + // UScriptStruct* + public FPackageIndex Struct; + + public override void Read(AssetBinaryReader reader) + { + base.Read(reader); + Struct = new FPackageIndex(reader.ReadInt32()); + } + + public override void Write(AssetBinaryWriter writer) + { + base.Write(writer); + writer.Write(Struct.Index); + } + } + + public class FNumericProperty : FProperty + { + public override void Read(AssetBinaryReader reader) + { + base.Read(reader); + } + + public override void Write(AssetBinaryWriter writer) + { + base.Write(writer); + } + } + + /// + /// This is a UAssetAPI-specific property that represents anything that we don't have special serialization for + /// + public class FGenericProperty : FProperty + { + public override void Read(AssetBinaryReader reader) + { + base.Read(reader); + } + + public override void Write(AssetBinaryWriter writer) + { + base.Write(writer); + } + } +} diff --git a/Translation/UAssetAPI/FieldTypes/UField.cs b/Translation/UAssetAPI/FieldTypes/UField.cs new file mode 100644 index 0000000..eb51b37 --- /dev/null +++ b/Translation/UAssetAPI/FieldTypes/UField.cs @@ -0,0 +1,423 @@ +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.FieldTypes +{ + /// + /// Base class of reflection data objects. + /// + public class UField + { + /// + /// Next Field in the linked list. Removed entirely in the custom version FFrameworkObjectVersion::RemoveUField_Next in favor of a regular array + /// + [DisplayIndexOrder(0)] + public FPackageIndex Next; + + public virtual void Read(AssetBinaryReader reader) + { + if (reader.Asset.GetCustomVersion() < FFrameworkObjectVersion.RemoveUField_Next) + { + Next = new FPackageIndex(reader.ReadInt32()); + } + } + + public virtual void Write(AssetBinaryWriter writer) + { + if (writer.Asset.GetCustomVersion() < FFrameworkObjectVersion.RemoveUField_Next) + { + writer.Write(Next.Index); + } + } + + public UField() + { + + } + } + + /// + /// An UnrealScript variable. + /// + public abstract class UProperty : UField + { + [DisplayIndexOrder(1)] + public EArrayDim ArrayDim; + [DisplayIndexOrder(2)] + public int ElementSize; + [DisplayIndexOrder(3)] + public EPropertyFlags PropertyFlags; + [DisplayIndexOrder(4)] + public FName RepNotifyFunc; + [DisplayIndexOrder(5)] + public ELifetimeCondition BlueprintReplicationCondition; + + public object RawValue; + + public void SetObject(object value) + { + RawValue = value; + } + + public T GetObject() + { + return (T)RawValue; + } + + public override void Read(AssetBinaryReader reader) + { + base.Read(reader); + ArrayDim = (EArrayDim)reader.ReadInt32(); + PropertyFlags = (EPropertyFlags)reader.ReadUInt64(); + RepNotifyFunc = reader.ReadFName(); + + if (reader.Asset.GetCustomVersion() >= FReleaseObjectVersion.PropertiesSerializeRepCondition) + { + BlueprintReplicationCondition = (ELifetimeCondition)reader.ReadByte(); + } + } + + public override void Write(AssetBinaryWriter writer) + { + base.Write(writer); + writer.Write((int)ArrayDim); + writer.Write((ulong)PropertyFlags); + writer.Write(RepNotifyFunc); + + if (writer.Asset.GetCustomVersion() >= FReleaseObjectVersion.PropertiesSerializeRepCondition) + { + writer.Write((byte)BlueprintReplicationCondition); + } + } + + public UProperty() + { + + } + } + + public class UEnumProperty : UProperty + { + ///A pointer to the UEnum represented by this property + [DisplayIndexOrder(6)] + public FPackageIndex Enum; + ///The FNumericProperty which represents the underlying type of the enum + [DisplayIndexOrder(7)] + public FPackageIndex UnderlyingProp; + + public override void Read(AssetBinaryReader reader) + { + base.Read(reader); + + Enum = new FPackageIndex(reader.ReadInt32()); + UnderlyingProp = new FPackageIndex(reader.ReadInt32()); + } + + public override void Write(AssetBinaryWriter writer) + { + base.Write(writer); + + writer.Write(Enum.Index); + writer.Write(UnderlyingProp.Index); + } + } + + public class UArrayProperty : UProperty + { + [DisplayIndexOrder(6)] + public FPackageIndex Inner; + + public override void Read(AssetBinaryReader reader) + { + base.Read(reader); + Inner = new FPackageIndex(reader.ReadInt32()); + } + + public override void Write(AssetBinaryWriter writer) + { + base.Write(writer); + writer.Write(Inner.Index); + } + } + + public class USetProperty : UProperty + { + [DisplayIndexOrder(6)] + public FPackageIndex ElementProp; + + public override void Read(AssetBinaryReader reader) + { + base.Read(reader); + ElementProp = new FPackageIndex(reader.ReadInt32()); + } + + public override void Write(AssetBinaryWriter writer) + { + base.Write(writer); + writer.Write(ElementProp.Index); + } + } + + public class UObjectProperty : UProperty + { + // UClass* + [DisplayIndexOrder(6)] + public FPackageIndex PropertyClass; + + public override void Read(AssetBinaryReader reader) + { + base.Read(reader); + PropertyClass = new FPackageIndex(reader.ReadInt32()); + } + + public override void Write(AssetBinaryWriter writer) + { + base.Write(writer); + writer.Write(PropertyClass.Index); + } + } + + public class USoftObjectProperty : UObjectProperty + { + + } + + public class ULazyObjectProperty : UObjectProperty + { + + } + + public class UClassProperty : UObjectProperty + { + // UClass* + [DisplayIndexOrder(7)] + public FPackageIndex MetaClass; + + public override void Read(AssetBinaryReader reader) + { + base.Read(reader); + MetaClass = new FPackageIndex(reader.ReadInt32()); + } + + public override void Write(AssetBinaryWriter writer) + { + base.Write(writer); + writer.Write(MetaClass.Index); + } + } + + public class USoftClassProperty : UObjectProperty + { + // UClass* + [DisplayIndexOrder(7)] + public FPackageIndex MetaClass; + + public override void Read(AssetBinaryReader reader) + { + base.Read(reader); + MetaClass = new FPackageIndex(reader.ReadInt32()); + } + + public override void Write(AssetBinaryWriter writer) + { + base.Write(writer); + writer.Write(MetaClass.Index); + } + } + + public class UDelegateProperty : UProperty + { + // UFunction* + [DisplayIndexOrder(6)] + public FPackageIndex SignatureFunction; + + public override void Read(AssetBinaryReader reader) + { + base.Read(reader); + SignatureFunction = new FPackageIndex(reader.ReadInt32()); + } + + public override void Write(AssetBinaryWriter writer) + { + base.Write(writer); + writer.Write(SignatureFunction.Index); + } + } + + public class UMulticastDelegateProperty : UDelegateProperty + { + + } + + public class UMulticastInlineDelegateProperty : UMulticastDelegateProperty + { + + } + + public class UInterfaceProperty : UProperty + { + // UFunction* + [DisplayIndexOrder(6)] + public FPackageIndex InterfaceClass; + + public override void Read(AssetBinaryReader reader) + { + base.Read(reader); + InterfaceClass = new FPackageIndex(reader.ReadInt32()); + } + + public override void Write(AssetBinaryWriter writer) + { + base.Write(writer); + writer.Write(InterfaceClass.Index); + } + } + + public class UMapProperty : UProperty + { + [DisplayIndexOrder(6)] + public FPackageIndex KeyProp; + [DisplayIndexOrder(7)] + public FPackageIndex ValueProp; + + public override void Read(AssetBinaryReader reader) + { + base.Read(reader); + KeyProp = new FPackageIndex(reader.ReadInt32()); + ValueProp = new FPackageIndex(reader.ReadInt32()); + } + + public override void Write(AssetBinaryWriter writer) + { + base.Write(writer); + writer.Write(KeyProp.Index); + writer.Write(ValueProp.Index); + } + } + + public class UBoolProperty : UProperty + { + [DisplayIndexOrder(6)] + public bool NativeBool; + + public override void Read(AssetBinaryReader reader) + { + base.Read(reader); + + ElementSize = reader.ReadByte(); + NativeBool = reader.ReadBoolean(); + } + + public override void Write(AssetBinaryWriter writer) + { + base.Write(writer); + writer.Write((byte)ElementSize); + writer.Write(NativeBool); + } + } + + public class UByteProperty : UProperty + { + /// A pointer to the UEnum represented by this property + [DisplayIndexOrder(6)] + public FPackageIndex Enum; + + public override void Read(AssetBinaryReader reader) + { + base.Read(reader); + Enum = new FPackageIndex(reader.ReadInt32()); + } + + public override void Write(AssetBinaryWriter writer) + { + base.Write(writer); + writer.Write(Enum.Index); + } + } + + public class UStructProperty : UProperty + { + // UScriptStruct* + [DisplayIndexOrder(6)] + public FPackageIndex Struct; + + public override void Read(AssetBinaryReader reader) + { + base.Read(reader); + Struct = new FPackageIndex(reader.ReadInt32()); + } + + public override void Write(AssetBinaryWriter writer) + { + base.Write(writer); + writer.Write(Struct.Index); + } + } + + public class UNumericProperty : UProperty + { + + } + + public class UDoubleProperty : UNumericProperty + { + + } + + public class UFloatProperty : UNumericProperty + { + + } + + public class UIntProperty : UNumericProperty + { + + } + + public class UInt8Property : UNumericProperty + { + + } + + public class UInt16Property : UNumericProperty + { + + } + + public class UInt64Property : UNumericProperty + { + + } + + public class UUInt8Property : UNumericProperty + { + + } + + public class UUInt16Property : UNumericProperty + { + + } + + public class UUInt64Property : UNumericProperty + { + + } + + public class UNameProperty : UProperty + { + + } + + public class UStrProperty : UProperty + { + + } + + /// + /// This is a UAssetAPI-specific property that represents anything that we don't have special serialization for + /// + public class UGenericProperty : UProperty + { + + } +} diff --git a/Translation/UAssetAPI/Import.cs b/Translation/UAssetAPI/Import.cs new file mode 100644 index 0000000..c9e3da5 --- /dev/null +++ b/Translation/UAssetAPI/Import.cs @@ -0,0 +1,30 @@ +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI +{ + /// + /// UObject resource type for objects that are referenced by this package, but contained within another package. + /// + public class Import : FObjectResource + { + public FName ClassPackage; + public FName ClassName; + + public Import(string classPackage, string className, FPackageIndex outerIndex, string objectName, UAsset asset) : base(new FName(asset, objectName), outerIndex) + { + ClassPackage = new FName(asset, classPackage); + ClassName = new FName(asset, className); + } + + public Import(FName classPackage, FName className, FPackageIndex outerIndex, FName objectName) : base(objectName, outerIndex) + { + ClassPackage = classPackage; + ClassName = className; + } + + public Import() + { + + } + } +} diff --git a/Translation/UAssetAPI/JSON/FNameJsonConverter.cs b/Translation/UAssetAPI/JSON/FNameJsonConverter.cs new file mode 100644 index 0000000..fe95425 --- /dev/null +++ b/Translation/UAssetAPI/JSON/FNameJsonConverter.cs @@ -0,0 +1,43 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI +{ + public class FNameJsonConverter : JsonConverter + { + public Dictionary ToBeFilled; + public int currentI = 0; + + public override bool CanConvert(Type objectType) + { + return objectType == typeof(FName); + } + + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + var realVal = (FName)value; + writer.WriteValue(realVal.DummyValue == null ? (realVal is null ? "null" : realVal.ToString()) : string.Empty); + } + + public override bool CanRead + { + get { return true; } + } + + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + if (reader.Value == null) return null; + var res = FName.DefineDummy(null, "temp", ++currentI); + ToBeFilled[res] = Convert.ToString(reader.Value); + return res; + } + + public FNameJsonConverter(Dictionary dict) : base() + { + ToBeFilled = dict; + } + } +} diff --git a/Translation/UAssetAPI/JSON/FPackageIndexJsonConverter.cs b/Translation/UAssetAPI/JSON/FPackageIndexJsonConverter.cs new file mode 100644 index 0000000..b530fe8 --- /dev/null +++ b/Translation/UAssetAPI/JSON/FPackageIndexJsonConverter.cs @@ -0,0 +1,29 @@ +using Newtonsoft.Json; +using System; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.JSON +{ + public class FPackageIndexJsonConverter : JsonConverter + { + public override bool CanConvert(Type objectType) + { + return objectType == typeof(FPackageIndex); + } + + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + writer.WriteValue((value as FPackageIndex).Index); + } + + public override bool CanRead + { + get { return true; } + } + + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + return new FPackageIndex(Convert.ToInt32(reader.Value)); + } + } +} diff --git a/Translation/UAssetAPI/JSON/FSignedZeroJsonConverter.cs b/Translation/UAssetAPI/JSON/FSignedZeroJsonConverter.cs new file mode 100644 index 0000000..79164d3 --- /dev/null +++ b/Translation/UAssetAPI/JSON/FSignedZeroJsonConverter.cs @@ -0,0 +1,55 @@ +using Newtonsoft.Json; +using System; +using System.Diagnostics; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.JSON +{ + public class FSignedZeroJsonConverter : JsonConverter + { + private static readonly decimal negativeZero = decimal.Negate(decimal.Zero); + + private static bool IsNegativeZero(double x) + { + return x == 0.0 && double.IsNegativeInfinity(1.0 / x); + } + + public override bool CanConvert(Type objectType) + { + return objectType == typeof(decimal) || objectType == typeof(float) || objectType == typeof(double); + } + + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + double us = Convert.ToDouble(value); + if (us == 0) + { + writer.WriteValue(IsNegativeZero(us) ? "-0" : "+0"); + } + else + { + writer.WriteValue(us); + } + } + + public override bool CanRead + { + get { return true; } + } + + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + if (reader.Value is null) return 0; + + if (reader.Value is string) + { + if (reader.Value == null || reader.Value.Equals("+0")) return Convert.ChangeType(0.0, objectType); + if (reader.Value.Equals("-0")) return Convert.ChangeType(negativeZero, objectType); + } + + object res = Convert.ChangeType(reader.Value, objectType); + if (res is null) return 0; + return res; + } + } +} diff --git a/Translation/UAssetAPI/JSON/FStringJsonConverter.cs b/Translation/UAssetAPI/JSON/FStringJsonConverter.cs new file mode 100644 index 0000000..70cbb78 --- /dev/null +++ b/Translation/UAssetAPI/JSON/FStringJsonConverter.cs @@ -0,0 +1,30 @@ +using Newtonsoft.Json; +using System; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.JSON +{ + public class FStringJsonConverter : JsonConverter + { + public override bool CanConvert(Type objectType) + { + return objectType == typeof(FString); + } + + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + writer.WriteValue((value as FString)?.Value); + } + + public override bool CanRead + { + get { return true; } + } + + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + if (reader.Value == null) return null; + return new FString(Convert.ToString(reader.Value)); + } + } +} diff --git a/Translation/UAssetAPI/JSON/FStringTableJsonConverter.cs b/Translation/UAssetAPI/JSON/FStringTableJsonConverter.cs new file mode 100644 index 0000000..34fda6d --- /dev/null +++ b/Translation/UAssetAPI/JSON/FStringTableJsonConverter.cs @@ -0,0 +1,66 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using System; +using System.Collections; +using System.Collections.Specialized; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.JSON +{ + public class FStringTableJsonConverter : JsonConverter + { + public override bool CanConvert(Type objectType) + { + return objectType == typeof(FStringTable); + } + + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + var realVal = (FStringTable)value; + + ICollection keys = ((IOrderedDictionary)value).Keys; + ICollection values = ((IOrderedDictionary)value).Values; + IEnumerator valueEnumerator = values.GetEnumerator(); + + writer.WriteStartObject(); + writer.WritePropertyName("TableNamespace"); + writer.WriteValue(realVal.TableNamespace?.Value); + writer.WritePropertyName("Value"); + writer.WriteStartArray(); + foreach (object key in keys) + { + valueEnumerator.MoveNext(); + + writer.WriteStartArray(); + serializer.Serialize(writer, key); + serializer.Serialize(writer, valueEnumerator.Current); + writer.WriteEndArray(); + } + writer.WriteEndArray(); + writer.WriteEndObject(); + } + + public override bool CanRead + { + get { return true; } + } + + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + var dictionary = new FStringTable(); + + JObject tableJson = JObject.Load(reader); + dictionary.TableNamespace = new FString(tableJson["TableNamespace"].ToObject()); + JArray tokens = (JArray)tableJson["Value"]; + + foreach (var eachToken in tokens) + { + FString key = eachToken[0].ToObject(serializer); + FString value = eachToken[1].ToObject(serializer); + dictionary.Add(key, value); + } + + return dictionary; + } + } +} \ No newline at end of file diff --git a/Translation/UAssetAPI/JSON/TMapJsonConverter.cs b/Translation/UAssetAPI/JSON/TMapJsonConverter.cs new file mode 100644 index 0000000..ba35d2b --- /dev/null +++ b/Translation/UAssetAPI/JSON/TMapJsonConverter.cs @@ -0,0 +1,81 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using System; +using System.Collections; +using System.Collections.Specialized; + +/* + The code in this file is modified from mattmc3's dotmore @ https://github.com/mattmc3/dotmore/tree/b032bbf871d46bffd698c9b7a233c533d9d2f0ebs for usage in UAssetAPI. + + The MIT License (MIT) + + Copyright (c) 2014 mattmc3 + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +*/ +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.JSON +{ + public class TMapJsonConverter : JsonConverter + { + public override bool CanConvert(Type objectType) + { + return typeof(IOrderedDictionary).IsAssignableFrom(objectType); + } + + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + ICollection keys = ((IOrderedDictionary)value).Keys; + ICollection values = ((IOrderedDictionary)value).Values; + IEnumerator valueEnumerator = values.GetEnumerator(); + + writer.WriteStartArray(); + foreach (object key in keys) + { + valueEnumerator.MoveNext(); + + writer.WriteStartArray(); + serializer.Serialize(writer, key); + serializer.Serialize(writer, valueEnumerator.Current); + writer.WriteEndArray(); + } + writer.WriteEndArray(); + } + + public override bool CanRead + { + get { return true; } + } + + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + var dictionary = new TMap(); + JToken tokens = JToken.Load(reader); + + foreach (var eachToken in tokens) + { + TKey key = eachToken[0].ToObject(serializer); + TValue value = eachToken[1].ToObject(serializer); + dictionary.Add(key, value); + } + return dictionary; + } + } +} \ No newline at end of file diff --git a/Translation/UAssetAPI/JSON/UAssetContractResolver.cs b/Translation/UAssetAPI/JSON/UAssetContractResolver.cs new file mode 100644 index 0000000..f98238a --- /dev/null +++ b/Translation/UAssetAPI/JSON/UAssetContractResolver.cs @@ -0,0 +1,27 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Serialization; +using System; +using System.Collections.Generic; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.JSON +{ + public class UAssetContractResolver : DefaultContractResolver + { + public Dictionary ToBeFilled; + + protected override JsonConverter ResolveContractConverter(Type objectType) + { + if (typeof(FName).IsAssignableFrom(objectType)) + { + return new FNameJsonConverter(ToBeFilled); + } + return base.ResolveContractConverter(objectType); + } + + public UAssetContractResolver(Dictionary toBeFilled) : base() + { + ToBeFilled = toBeFilled; + } + } +} diff --git a/Translation/UAssetAPI/Kismet/Bytecode/EBlueprintTextLiteralType.cs b/Translation/UAssetAPI/Kismet/Bytecode/EBlueprintTextLiteralType.cs new file mode 100644 index 0000000..5a56478 --- /dev/null +++ b/Translation/UAssetAPI/Kismet/Bytecode/EBlueprintTextLiteralType.cs @@ -0,0 +1,29 @@ +namespace UAssetAPI.Kismet.Bytecode +{ + /// + /// Kinds of text literals + /// + public enum EBlueprintTextLiteralType : byte + { + /// + /// Text is an empty string. The bytecode contains no strings, and you should use FText::GetEmpty() to initialize the FText instance. + /// + Empty, + /// + /// Text is localized. The bytecode will contain three strings - source, key, and namespace - and should be loaded via FInternationalization + /// + LocalizedText, + /// + /// Text is culture invariant. The bytecode will contain one string, and you should use FText::AsCultureInvariant to initialize the FText instance. + /// + InvariantText, + /// + /// Text is a literal FString. The bytecode will contain one string, and you should use FText::FromString to initialize the FText instance. + /// + LiteralString, + /// + /// Text is from a string table. The bytecode will contain an object pointer (not used) and two strings - the table ID, and key - and should be found via FText::FromStringTable + /// + StringTableEntry + } +} diff --git a/Translation/UAssetAPI/Kismet/Bytecode/EExprToken.cs b/Translation/UAssetAPI/Kismet/Bytecode/EExprToken.cs new file mode 100644 index 0000000..988f9e0 --- /dev/null +++ b/Translation/UAssetAPI/Kismet/Bytecode/EExprToken.cs @@ -0,0 +1,186 @@ +namespace UAssetAPI.Kismet.Bytecode +{ + /// + /// Evaluatable expression item types. + /// + public enum EExprToken + { + /// A local variable. + EX_LocalVariable = 0x00, + /// An object variable. + EX_InstanceVariable = 0x01, + /// Default variable for a class context. + EX_DefaultVariable = 0x02, + /// Return from function. + EX_Return = 0x04, + /// Goto a local address in code. + EX_Jump = 0x06, + /// Goto if not expression. + EX_JumpIfNot = 0x07, + /// Assertion. + EX_Assert = 0x09, + /// No operation. + EX_Nothing = 0x0B, + /// Assign an arbitrary size value to a variable. + EX_Let = 0x0F, + /// Class default object context. + EX_ClassContext = 0x12, + /// Metaclass cast. + EX_MetaCast = 0x13, + /// Let boolean variable. + EX_LetBool = 0x14, + /// end of default value for optional function parameter + EX_EndParmValue = 0x15, + /// End of function call parameters. + EX_EndFunctionParms = 0x16, + /// Self object. + EX_Self = 0x17, + /// Skippable expression. + EX_Skip = 0x18, + /// Call a function through an object context. + EX_Context = 0x19, + /// Call a function through an object context (can fail silently if the context is NULL; only generated for functions that don't have output or return values). + EX_Context_FailSilent = 0x1A, + /// A function call with parameters. + EX_VirtualFunction = 0x1B, + /// A prebound function call with parameters. + EX_FinalFunction = 0x1C, + /// Int constant. + EX_IntConst = 0x1D, + /// Floating point constant. + EX_FloatConst = 0x1E, + /// String constant. + EX_StringConst = 0x1F, + /// An object constant. + EX_ObjectConst = 0x20, + /// A name constant. + EX_NameConst = 0x21, + /// A rotation constant. + EX_RotationConst = 0x22, + /// A vector constant. + EX_VectorConst = 0x23, + /// A byte constant. + EX_ByteConst = 0x24, + /// Zero. + EX_IntZero = 0x25, + /// One. + EX_IntOne = 0x26, + /// Bool True. + EX_True = 0x27, + /// Bool False. + EX_False = 0x28, + /// FText constant + EX_TextConst = 0x29, + /// NoObject. + EX_NoObject = 0x2A, + /// A transform constant + EX_TransformConst = 0x2B, + /// Int constant that requires 1 byte. + EX_IntConstByte = 0x2C, + /// A null interface (similar to EX_NoObject, but for interfaces) + EX_NoInterface = 0x2D, + /// Safe dynamic class casting. + EX_DynamicCast = 0x2E, + /// An arbitrary UStruct constant + EX_StructConst = 0x2F, + /// End of UStruct constant + EX_EndStructConst = 0x30, + /// Set the value of arbitrary array + EX_SetArray = 0x31, + EX_EndArray = 0x32, + /// FProperty constant. + EX_PropertyConst = 0x33, + /// Unicode string constant. + EX_UnicodeStringConst = 0x34, + /// 64-bit integer constant. + EX_Int64Const = 0x35, + /// 64-bit unsigned integer constant. + EX_UInt64Const = 0x36, + /// A casting operator for primitives which reads the type as the subsequent byte + EX_PrimitiveCast = 0x38, + EX_SetSet = 0x39, + EX_EndSet = 0x3A, + EX_SetMap = 0x3B, + EX_EndMap = 0x3C, + EX_SetConst = 0x3D, + EX_EndSetConst = 0x3E, + EX_MapConst = 0x3F, + EX_EndMapConst = 0x40, + /// Context expression to address a property within a struct + EX_StructMemberContext = 0x42, + /// Assignment to a multi-cast delegate + EX_LetMulticastDelegate = 0x43, + /// Assignment to a delegate + EX_LetDelegate = 0x44, + /// Special instructions to quickly call a virtual function that we know is going to run only locally + EX_LocalVirtualFunction = 0x45, + /// Special instructions to quickly call a final function that we know is going to run only locally + EX_LocalFinalFunction = 0x46, + /// local out (pass by reference) function parameter + EX_LocalOutVariable = 0x48, + EX_DeprecatedOp4A = 0x4A, + /// const reference to a delegate or normal function object + EX_InstanceDelegate = 0x4B, + /// push an address on to the execution flow stack for future execution when a EX_PopExecutionFlow is executed. Execution continues on normally and doesn't change to the pushed address. + EX_PushExecutionFlow = 0x4C, + /// continue execution at the last address previously pushed onto the execution flow stack. + EX_PopExecutionFlow = 0x4D, + /// Goto a local address in code, specified by an integer value. + EX_ComputedJump = 0x4E, + /// continue execution at the last address previously pushed onto the execution flow stack, if the condition is not true. + EX_PopExecutionFlowIfNot = 0x4F, + /// Breakpoint. Only observed in the editor, otherwise it behaves like EX_Nothing. + EX_Breakpoint = 0x50, + /// Call a function through a native interface variable + EX_InterfaceContext = 0x51, + /// Converting an object reference to native interface variable + EX_ObjToInterfaceCast = 0x52, + /// Last byte in script code + EX_EndOfScript = 0x53, + /// Converting an interface variable reference to native interface variable + EX_CrossInterfaceCast = 0x54, + /// Converting an interface variable reference to an object + EX_InterfaceToObjCast = 0x55, + /// Trace point. Only observed in the editor, otherwise it behaves like EX_Nothing. + EX_WireTracepoint = 0x5A, + /// A CodeSizeSkipOffset constant + EX_SkipOffsetConst = 0x5B, + /// Adds a delegate to a multicast delegate's targets + EX_AddMulticastDelegate = 0x5C, + /// Clears all delegates in a multicast target + EX_ClearMulticastDelegate = 0x5D, + /// Trace point. Only observed in the editor, otherwise it behaves like EX_Nothing. + EX_Tracepoint = 0x5E, + /// assign to any object ref pointer + EX_LetObj = 0x5F, + /// assign to a weak object pointer + EX_LetWeakObjPtr = 0x60, + /// bind object and name to delegate + EX_BindDelegate = 0x61, + /// Remove a delegate from a multicast delegate's targets + EX_RemoveMulticastDelegate = 0x62, + /// Call multicast delegate + EX_CallMulticastDelegate = 0x63, + EX_LetValueOnPersistentFrame = 0x64, + EX_ArrayConst = 0x65, + EX_EndArrayConst = 0x66, + EX_SoftObjectConst = 0x67, + /// static pure function from on local call space + EX_CallMath = 0x68, + EX_SwitchValue = 0x69, + /// Instrumentation event + EX_InstrumentationEvent = 0x6A, + EX_ArrayGetByRef = 0x6B, + /// Sparse data variable + EX_ClassSparseDataVariable = 0x6C, + EX_FieldPathConst = 0x6D, + EX_Max = 0x100, + }; + + public enum ECastToken { + ObjectToInterface = 0x46, + ObjectToBool = 0x47, + InterfaceToBool = 0x49, + Max = 0xFF, + }; +} diff --git a/Translation/UAssetAPI/Kismet/Bytecode/EScriptInstrumentationType.cs b/Translation/UAssetAPI/Kismet/Bytecode/EScriptInstrumentationType.cs new file mode 100644 index 0000000..c5c4186 --- /dev/null +++ b/Translation/UAssetAPI/Kismet/Bytecode/EScriptInstrumentationType.cs @@ -0,0 +1,22 @@ +namespace UAssetAPI.Kismet.Bytecode +{ + public enum EScriptInstrumentationType : byte { + Class = 0, + ClassScope, + Instance, + Event, + InlineEvent, + ResumeEvent, + PureNodeEntry, + NodeDebugSite, + NodeEntry, + NodeExit, + PushState, + RestoreState, + ResetState, + SuspendState, + PopState, + TunnelEndOfThread, + Stop + } +} diff --git a/Translation/UAssetAPI/Kismet/Bytecode/ExpressionSerializer.cs b/Translation/UAssetAPI/Kismet/Bytecode/ExpressionSerializer.cs new file mode 100644 index 0000000..444e962 --- /dev/null +++ b/Translation/UAssetAPI/Kismet/Bytecode/ExpressionSerializer.cs @@ -0,0 +1,311 @@ +using System; +using UAssetAPI.Kismet.Bytecode.Expressions; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.Kismet.Bytecode +{ + public static class ExpressionSerializer + { + public static KismetExpression ReadExpression(AssetBinaryReader reader) + { + KismetExpression res = null; + EExprToken token = (EExprToken)reader.ReadByte(); + switch (token) + { + case EExprToken.EX_LocalVariable: + res = new EX_LocalVariable(); + break; + case EExprToken.EX_InstanceVariable: + res = new EX_InstanceVariable(); + break; + case EExprToken.EX_DefaultVariable: + res = new EX_DefaultVariable(); + break; + case EExprToken.EX_Return: + res = new EX_Return(); + break; + case EExprToken.EX_Jump: + res = new EX_Jump(); + break; + case EExprToken.EX_JumpIfNot: + res = new EX_JumpIfNot(); + break; + case EExprToken.EX_Assert: + res = new EX_Assert(); + break; + case EExprToken.EX_Nothing: + res = new EX_Nothing(); + break; + case EExprToken.EX_Let: + res = new EX_Let(); + break; + case EExprToken.EX_ClassContext: + res = new EX_ClassContext(); + break; + case EExprToken.EX_MetaCast: + res = new EX_MetaCast(); + break; + case EExprToken.EX_LetBool: + res = new EX_LetBool(); + break; + case EExprToken.EX_EndParmValue: + res = new EX_EndParmValue(); + break; + case EExprToken.EX_EndFunctionParms: + res = new EX_EndFunctionParms(); + break; + case EExprToken.EX_Self: + res = new EX_Self(); + break; + case EExprToken.EX_Skip: + res = new EX_Skip(); + break; + case EExprToken.EX_Context: + res = new EX_Context(); + break; + case EExprToken.EX_Context_FailSilent: + res = new EX_Context_FailSilent(); + break; + case EExprToken.EX_VirtualFunction: + res = new EX_VirtualFunction(); + break; + case EExprToken.EX_FinalFunction: + res = new EX_FinalFunction(); + break; + case EExprToken.EX_IntConst: + res = new EX_IntConst(); + break; + case EExprToken.EX_FloatConst: + res = new EX_FloatConst(); + break; + case EExprToken.EX_StringConst: + res = new EX_StringConst(); + break; + case EExprToken.EX_ObjectConst: + res = new EX_ObjectConst(); + break; + case EExprToken.EX_NameConst: + res = new EX_NameConst(); + break; + case EExprToken.EX_RotationConst: + res = new EX_RotationConst(); + break; + case EExprToken.EX_VectorConst: + res = new EX_VectorConst(); + break; + case EExprToken.EX_ByteConst: + res = new EX_ByteConst(); + break; + case EExprToken.EX_IntZero: + res = new EX_IntZero(); + break; + case EExprToken.EX_IntOne: + res = new EX_IntOne(); + break; + case EExprToken.EX_True: + res = new EX_True(); + break; + case EExprToken.EX_False: + res = new EX_False(); + break; + case EExprToken.EX_TextConst: + res = new EX_TextConst(); + break; + case EExprToken.EX_NoObject: + res = new EX_NoObject(); + break; + case EExprToken.EX_TransformConst: + res = new EX_TransformConst(); + break; + case EExprToken.EX_IntConstByte: + res = new EX_IntConstByte(); + break; + case EExprToken.EX_NoInterface: + res = new EX_NoInterface(); + break; + case EExprToken.EX_DynamicCast: + res = new EX_DynamicCast(); + break; + case EExprToken.EX_StructConst: + res = new EX_StructConst(); + break; + case EExprToken.EX_EndStructConst: + res = new EX_EndStructConst(); + break; + case EExprToken.EX_SetArray: + res = new EX_SetArray(); + break; + case EExprToken.EX_EndArray: + res = new EX_EndArray(); + break; + case EExprToken.EX_PropertyConst: + res = new EX_PropertyConst(); + break; + case EExprToken.EX_UnicodeStringConst: + res = new EX_UnicodeStringConst(); + break; + case EExprToken.EX_Int64Const: + res = new EX_Int64Const(); + break; + case EExprToken.EX_UInt64Const: + res = new EX_UInt64Const(); + break; + case EExprToken.EX_PrimitiveCast: + res = new EX_PrimitiveCast(); + break; + case EExprToken.EX_SetSet: + res = new EX_SetSet(); + break; + case EExprToken.EX_EndSet: + res = new EX_EndSet(); + break; + case EExprToken.EX_SetMap: + res = new EX_SetMap(); + break; + case EExprToken.EX_EndMap: + res = new EX_EndMap(); + break; + case EExprToken.EX_SetConst: + res = new EX_SetConst(); + break; + case EExprToken.EX_EndSetConst: + res = new EX_EndSetConst(); + break; + case EExprToken.EX_MapConst: + res = new EX_MapConst(); + break; + case EExprToken.EX_EndMapConst: + res = new EX_EndMapConst(); + break; + case EExprToken.EX_StructMemberContext: + res = new EX_StructMemberContext(); + break; + case EExprToken.EX_LetMulticastDelegate: + res = new EX_LetMulticastDelegate(); + break; + case EExprToken.EX_LetDelegate: + res = new EX_LetDelegate(); + break; + case EExprToken.EX_LocalVirtualFunction: + res = new EX_LocalVirtualFunction(); + break; + case EExprToken.EX_LocalFinalFunction: + res = new EX_LocalFinalFunction(); + break; + case EExprToken.EX_LocalOutVariable: + res = new EX_LocalOutVariable(); + break; + case EExprToken.EX_DeprecatedOp4A: + res = new EX_DeprecatedOp4A(); + break; + case EExprToken.EX_InstanceDelegate: + res = new EX_InstanceDelegate(); + break; + case EExprToken.EX_PushExecutionFlow: + res = new EX_PushExecutionFlow(); + break; + case EExprToken.EX_PopExecutionFlow: + res = new EX_PopExecutionFlow(); + break; + case EExprToken.EX_ComputedJump: + res = new EX_ComputedJump(); + break; + case EExprToken.EX_PopExecutionFlowIfNot: + res = new EX_PopExecutionFlowIfNot(); + break; + case EExprToken.EX_Breakpoint: + res = new EX_Breakpoint(); + break; + case EExprToken.EX_InterfaceContext: + res = new EX_InterfaceContext(); + break; + case EExprToken.EX_ObjToInterfaceCast: + res = new EX_ObjToInterfaceCast(); + break; + case EExprToken.EX_EndOfScript: + res = new EX_EndOfScript(); + break; + case EExprToken.EX_CrossInterfaceCast: + res = new EX_CrossInterfaceCast(); + break; + case EExprToken.EX_InterfaceToObjCast: + res = new EX_InterfaceToObjCast(); + break; + case EExprToken.EX_WireTracepoint: + res = new EX_WireTracepoint(); + break; + case EExprToken.EX_SkipOffsetConst: + res = new EX_SkipOffsetConst(); + break; + case EExprToken.EX_AddMulticastDelegate: + res = new EX_AddMulticastDelegate(); + break; + case EExprToken.EX_ClearMulticastDelegate: + res = new EX_ClearMulticastDelegate(); + break; + case EExprToken.EX_Tracepoint: + res = new EX_Tracepoint(); + break; + case EExprToken.EX_LetObj: + res = new EX_LetObj(); + break; + case EExprToken.EX_LetWeakObjPtr: + res = new EX_LetWeakObjPtr(); + break; + case EExprToken.EX_BindDelegate: + res = new EX_BindDelegate(); + break; + case EExprToken.EX_RemoveMulticastDelegate: + res = new EX_RemoveMulticastDelegate(); + break; + case EExprToken.EX_CallMulticastDelegate: + res = new EX_CallMulticastDelegate(); + break; + case EExprToken.EX_LetValueOnPersistentFrame: + res = new EX_LetValueOnPersistentFrame(); + break; + case EExprToken.EX_ArrayConst: + res = new EX_ArrayConst(); + break; + case EExprToken.EX_EndArrayConst: + res = new EX_EndArrayConst(); + break; + case EExprToken.EX_SoftObjectConst: + res = new EX_SoftObjectConst(); + break; + case EExprToken.EX_CallMath: + res = new EX_CallMath(); + break; + case EExprToken.EX_SwitchValue: + res = new EX_SwitchValue(); + break; + case EExprToken.EX_InstrumentationEvent: + res = new EX_InstrumentationEvent(); + break; + case EExprToken.EX_ArrayGetByRef: + res = new EX_ArrayGetByRef(); + break; + case EExprToken.EX_ClassSparseDataVariable: + res = new EX_ClassSparseDataVariable(); + break; + case EExprToken.EX_FieldPathConst: + res = new EX_FieldPathConst(); + break; + default: + throw new NotImplementedException("Unimplemented token " + token); + } + + if (res != null) + { + res.Read(reader); + } + return res; + } + + public static int WriteExpression(KismetExpression expr, AssetBinaryWriter writer) + { + writer.Write((byte)expr.Token); + return expr.Write(writer) + sizeof(byte); + } + } +} diff --git a/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_AddMulticastDelegate.cs b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_AddMulticastDelegate.cs new file mode 100644 index 0000000..abd0271 --- /dev/null +++ b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_AddMulticastDelegate.cs @@ -0,0 +1,56 @@ +using Newtonsoft.Json; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.Kismet.Bytecode.Expressions +{ + /// + /// A single Kismet bytecode instruction, corresponding to the instruction. + /// + public class EX_AddMulticastDelegate : KismetExpression + { + /// + /// The token of this expression. + /// + public override EExprToken Token { get { return EExprToken.EX_AddMulticastDelegate; } } + + /// + /// Delegate property to assign to. + /// + [JsonProperty] + public KismetExpression Delegate; + + /// + /// Delegate to add to the MC delegate for broadcast. + /// + [JsonProperty] + public KismetExpression DelegateToAdd; + + public EX_AddMulticastDelegate() + { + + } + + /// + /// Reads out the expression from a BinaryReader. + /// + /// The BinaryReader to read from. + public override void Read(AssetBinaryReader reader) + { + Delegate = ExpressionSerializer.ReadExpression(reader); + DelegateToAdd = ExpressionSerializer.ReadExpression(reader); + } + + /// + /// Writes the expression to a BinaryWriter. + /// + /// The BinaryWriter to write from. + /// The iCode offset of the data that was written. + public override int Write(AssetBinaryWriter writer) + { + int offset = 0; + offset += ExpressionSerializer.WriteExpression(Delegate, writer); + offset += ExpressionSerializer.WriteExpression(DelegateToAdd, writer); + return offset; + } + } +} diff --git a/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_ArrayConst.cs b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_ArrayConst.cs new file mode 100644 index 0000000..5a09086 --- /dev/null +++ b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_ArrayConst.cs @@ -0,0 +1,62 @@ +using Newtonsoft.Json; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.Kismet.Bytecode.Expressions +{ + /// + /// A single Kismet bytecode instruction, corresponding to the instruction. + /// + public class EX_ArrayConst : KismetExpression + { + /// + /// The token of this expression. + /// + public override EExprToken Token { get { return EExprToken.EX_ArrayConst; } } + + /// + /// Pointer to this constant's inner property (FProperty*). + /// + [JsonProperty] + public KismetPropertyPointer InnerProperty; + + /// + /// Array constant entries. + /// + [JsonProperty] + public KismetExpression[] Elements; + + public EX_ArrayConst() + { + + } + + /// + /// Reads out the expression from a BinaryReader. + /// + /// The BinaryReader to read from. + public override void Read(AssetBinaryReader reader) + { + InnerProperty = reader.XFER_PROP_POINTER(); + int numEntries = reader.ReadInt32(); // Number of elements + Elements = reader.ReadExpressionArray(EExprToken.EX_EndArrayConst); + } + + /// + /// Writes the expression to a BinaryWriter. + /// + /// The BinaryWriter to write from. + /// The iCode offset of the data that was written. + public override int Write(AssetBinaryWriter writer) + { + int offset = 0; + offset += writer.XFER_PROP_POINTER(InnerProperty); + writer.Write(Elements.Length); offset += sizeof(int); + for (int i = 0; i < Elements.Length; i++) + { + offset += ExpressionSerializer.WriteExpression(Elements[i], writer); + } + offset += ExpressionSerializer.WriteExpression(new EX_EndArrayConst(), writer); + return offset; + } + } +} diff --git a/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_ArrayGetByRef.cs b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_ArrayGetByRef.cs new file mode 100644 index 0000000..a63ce02 --- /dev/null +++ b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_ArrayGetByRef.cs @@ -0,0 +1,56 @@ +using Newtonsoft.Json; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.Kismet.Bytecode.Expressions +{ + /// + /// A single Kismet bytecode instruction, corresponding to the instruction. + /// + public class EX_ArrayGetByRef : KismetExpression + { + /// + /// The token of this expression. + /// + public override EExprToken Token { get { return EExprToken.EX_ArrayGetByRef; } } + + /// + /// The array variable. + /// + [JsonProperty] + public KismetExpression ArrayVariable; + + /// + /// The index to access in the array. + /// + [JsonProperty] + public KismetExpression ArrayIndex; + + public EX_ArrayGetByRef() + { + + } + + /// + /// Reads out the expression from a BinaryReader. + /// + /// The BinaryReader to read from. + public override void Read(AssetBinaryReader reader) + { + ArrayVariable = ExpressionSerializer.ReadExpression(reader); + ArrayIndex = ExpressionSerializer.ReadExpression(reader); + } + + /// + /// Writes the expression to a BinaryWriter. + /// + /// The BinaryWriter to write from. + /// The iCode offset of the data that was written. + public override int Write(AssetBinaryWriter writer) + { + int offset = 0; + offset += ExpressionSerializer.WriteExpression(ArrayVariable, writer); + offset += ExpressionSerializer.WriteExpression(ArrayIndex, writer); + return offset; + } + } +} diff --git a/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_Assert.cs b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_Assert.cs new file mode 100644 index 0000000..a3bec19 --- /dev/null +++ b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_Assert.cs @@ -0,0 +1,64 @@ +using Newtonsoft.Json; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.Kismet.Bytecode.Expressions +{ + /// + /// A single Kismet bytecode instruction, corresponding to the instruction. + /// + public class EX_Assert : KismetExpression + { + /// + /// The token of this expression. + /// + public override EExprToken Token { get { return EExprToken.EX_Assert; } } + + /// + /// Line number. + /// + [JsonProperty] + public ushort LineNumber; + + /// + /// Whether or not this assertion is in debug mode. + /// + [JsonProperty] + public bool DebugMode; + + /// + /// Expression to assert. + /// + [JsonProperty] + public KismetExpression AssertExpression; + + public EX_Assert() + { + + } + + /// + /// Reads out the expression from a BinaryReader. + /// + /// The BinaryReader to read from. + public override void Read(AssetBinaryReader reader) + { + LineNumber = reader.ReadUInt16(); + DebugMode = reader.ReadBoolean(); + AssertExpression = ExpressionSerializer.ReadExpression(reader); + } + + /// + /// Writes the expression to a BinaryWriter. + /// + /// The BinaryWriter to write from. + /// The iCode offset of the data that was written. + public override int Write(AssetBinaryWriter writer) + { + int offset = 0; + writer.Write(LineNumber); offset += sizeof(ushort); + writer.Write(DebugMode); offset += sizeof(bool); + offset += ExpressionSerializer.WriteExpression(AssertExpression, writer); + return offset; + } + } +} diff --git a/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_BindDelegate.cs b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_BindDelegate.cs new file mode 100644 index 0000000..5d621ad --- /dev/null +++ b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_BindDelegate.cs @@ -0,0 +1,64 @@ +using Newtonsoft.Json; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.Kismet.Bytecode.Expressions +{ + /// + /// A single Kismet bytecode instruction, corresponding to the instruction. + /// + public class EX_BindDelegate : KismetExpression + { + /// + /// The token of this expression. + /// + public override EExprToken Token { get { return EExprToken.EX_BindDelegate; } } + + /// + /// The name of the function assigned to the delegate. + /// + [JsonProperty] + public FName FunctionName; + + /// + /// Delegate property to assign to. + /// + [JsonProperty] + public KismetExpression Delegate; + + /// + /// Object to bind. + /// + [JsonProperty] + public KismetExpression ObjectTerm; + + public EX_BindDelegate() + { + + } + + /// + /// Reads out the expression from a BinaryReader. + /// + /// The BinaryReader to read from. + public override void Read(AssetBinaryReader reader) + { + FunctionName = reader.XFER_FUNC_NAME(); + Delegate = ExpressionSerializer.ReadExpression(reader); + ObjectTerm = ExpressionSerializer.ReadExpression(reader); + } + + /// + /// Writes the expression to a BinaryWriter. + /// + /// The BinaryWriter to write from. + /// The iCode offset of the data that was written. + public override int Write(AssetBinaryWriter writer) + { + int offset = 0; + offset += writer.XFER_FUNC_NAME(FunctionName); + offset += ExpressionSerializer.WriteExpression(Delegate, writer); + offset += ExpressionSerializer.WriteExpression(ObjectTerm, writer); + return offset; + } + } +} diff --git a/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_Breakpoint.cs b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_Breakpoint.cs new file mode 100644 index 0000000..c25cb10 --- /dev/null +++ b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_Breakpoint.cs @@ -0,0 +1,37 @@ +namespace UAssetAPI.Kismet.Bytecode.Expressions +{ + /// + /// A single Kismet bytecode instruction, corresponding to the instruction. + /// + public class EX_Breakpoint : KismetExpression + { + /// + /// The token of this expression. + /// + public override EExprToken Token { get { return EExprToken.EX_Breakpoint; } } + + public EX_Breakpoint() + { + + } + + /// + /// Reads out the expression from a BinaryReader. + /// + /// The BinaryReader to read from. + public override void Read(AssetBinaryReader reader) + { + + } + + /// + /// Writes the expression to a BinaryWriter. + /// + /// The BinaryWriter to write from. + /// The iCode offset of the data that was written. + public override int Write(AssetBinaryWriter writer) + { + return 0; + } + } +} diff --git a/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_ByteConst.cs b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_ByteConst.cs new file mode 100644 index 0000000..098efa2 --- /dev/null +++ b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_ByteConst.cs @@ -0,0 +1,38 @@ +namespace UAssetAPI.Kismet.Bytecode.Expressions +{ + /// + /// A single Kismet bytecode instruction, corresponding to the instruction. + /// + public class EX_ByteConst : KismetExpression + { + /// + /// The token of this expression. + /// + public override EExprToken Token { get { return EExprToken.EX_ByteConst; } } + + public EX_ByteConst() + { + + } + + /// + /// Reads out the expression from a BinaryReader. + /// + /// The BinaryReader to read from. + public override void Read(AssetBinaryReader reader) + { + Value = reader.ReadByte(); + } + + /// + /// Writes the expression to a BinaryWriter. + /// + /// The BinaryWriter to write from. + /// The iCode offset of the data that was written. + public override int Write(AssetBinaryWriter writer) + { + writer.Write(Value); + return sizeof(byte); + } + } +} diff --git a/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_CallMath.cs b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_CallMath.cs new file mode 100644 index 0000000..17268e4 --- /dev/null +++ b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_CallMath.cs @@ -0,0 +1,37 @@ +namespace UAssetAPI.Kismet.Bytecode.Expressions +{ + /// + /// A single Kismet bytecode instruction, corresponding to the instruction. + /// + public class EX_CallMath : EX_FinalFunction + { + /// + /// The token of this expression. + /// + public override EExprToken Token { get { return EExprToken.EX_CallMath; } } + + public EX_CallMath() : base() + { + + } + + /// + /// Reads out the expression from a BinaryReader. + /// + /// The BinaryReader to read from. + public override void Read(AssetBinaryReader reader) + { + base.Read(reader); + } + + /// + /// Writes the expression to a BinaryWriter. + /// + /// The BinaryWriter to write from. + /// The iCode offset of the data that was written. + public override int Write(AssetBinaryWriter writer) + { + return base.Write(writer); + } + } +} diff --git a/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_CallMulticastDelegate.cs b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_CallMulticastDelegate.cs new file mode 100644 index 0000000..9577b2a --- /dev/null +++ b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_CallMulticastDelegate.cs @@ -0,0 +1,58 @@ +using Newtonsoft.Json; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.Kismet.Bytecode.Expressions +{ + /// + /// A single Kismet bytecode instruction, corresponding to the instruction. + /// + public class EX_CallMulticastDelegate : EX_FinalFunction + { + /// + /// The token of this expression. + /// + public override EExprToken Token { get { return EExprToken.EX_CallMulticastDelegate; } } + + /// + /// Delegate property. + /// + [JsonProperty] + public KismetExpression Delegate; + + public EX_CallMulticastDelegate() + { + + } + + /// + /// Reads out the expression from a BinaryReader. + /// + /// The BinaryReader to read from. + public override void Read(AssetBinaryReader reader) + { + StackNode = reader.XFER_FUNC_POINTER(); + Delegate = ExpressionSerializer.ReadExpression(reader); + Parameters = reader.ReadExpressionArray(EExprToken.EX_EndFunctionParms); + + } + + /// + /// Writes the expression to a BinaryWriter. + /// + /// The BinaryWriter to write from. + /// The iCode offset of the data that was written. + public override int Write(AssetBinaryWriter writer) + { + int offset = 0; + offset += writer.XFER_FUNC_POINTER(StackNode); + offset += ExpressionSerializer.WriteExpression(Delegate, writer); + + for (int i = 0; i < Parameters.Length; i++) + { + offset += ExpressionSerializer.WriteExpression(Parameters[i], writer); + } + offset += ExpressionSerializer.WriteExpression(new EX_EndFunctionParms(), writer); + return offset; + } + } +} diff --git a/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_ClassContext.cs b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_ClassContext.cs new file mode 100644 index 0000000..7de3e22 --- /dev/null +++ b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_ClassContext.cs @@ -0,0 +1,37 @@ +namespace UAssetAPI.Kismet.Bytecode.Expressions +{ + /// + /// A single Kismet bytecode instruction, corresponding to the instruction. + /// + public class EX_ClassContext : EX_Context + { + /// + /// The token of this expression. + /// + public override EExprToken Token { get { return EExprToken.EX_ClassContext; } } + + public EX_ClassContext() + { + + } + + /// + /// Reads out the expression from a BinaryReader. + /// + /// The BinaryReader to read from. + public override void Read(AssetBinaryReader reader) + { + base.Read(reader); + } + + /// + /// Writes the expression to a BinaryWriter. + /// + /// The BinaryWriter to write from. + /// The iCode offset of the data that was written. + public override int Write(AssetBinaryWriter writer) + { + return base.Write(writer); + } + } +} diff --git a/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_ClassSparseDataVariable.cs b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_ClassSparseDataVariable.cs new file mode 100644 index 0000000..ada34fc --- /dev/null +++ b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_ClassSparseDataVariable.cs @@ -0,0 +1,46 @@ +using Newtonsoft.Json; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.Kismet.Bytecode.Expressions +{ + /// + /// A single Kismet bytecode instruction, corresponding to the instruction. + /// + public class EX_ClassSparseDataVariable : KismetExpression + { + /// + /// The token of this expression. + /// + public override EExprToken Token { get { return EExprToken.EX_ClassSparseDataVariable; } } + + /// + /// A pointer to the variable in question. + /// + [JsonProperty] + public KismetPropertyPointer Variable; + + public EX_ClassSparseDataVariable() + { + + } + + /// + /// Reads out the expression from a BinaryReader. + /// + /// The BinaryReader to read from. + public override void Read(AssetBinaryReader reader) + { + Variable = reader.XFER_PROP_POINTER(); + } + + /// + /// Writes the expression to a BinaryWriter. + /// + /// The BinaryWriter to write from. + /// The iCode offset of the data that was written. + public override int Write(AssetBinaryWriter writer) + { + return writer.XFER_PROP_POINTER(Variable); + } + } +} diff --git a/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_ClearMulticastDelegate.cs b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_ClearMulticastDelegate.cs new file mode 100644 index 0000000..4c3cb06 --- /dev/null +++ b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_ClearMulticastDelegate.cs @@ -0,0 +1,46 @@ +using Newtonsoft.Json; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.Kismet.Bytecode.Expressions +{ + /// + /// A single Kismet bytecode instruction, corresponding to the instruction. + /// + public class EX_ClearMulticastDelegate : KismetExpression + { + /// + /// The token of this expression. + /// + public override EExprToken Token { get { return EExprToken.EX_ClearMulticastDelegate; } } + + /// + /// Delegate property to clear. + /// + [JsonProperty] + public KismetExpression DelegateToClear; + + public EX_ClearMulticastDelegate() + { + + } + + /// + /// Reads out the expression from a BinaryReader. + /// + /// The BinaryReader to read from. + public override void Read(AssetBinaryReader reader) + { + DelegateToClear = ExpressionSerializer.ReadExpression(reader); + } + + /// + /// Writes the expression to a BinaryWriter. + /// + /// The BinaryWriter to write from. + /// The iCode offset of the data that was written. + public override int Write(AssetBinaryWriter writer) + { + return ExpressionSerializer.WriteExpression(DelegateToClear, writer); + } + } +} diff --git a/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_ComputedJump.cs b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_ComputedJump.cs new file mode 100644 index 0000000..c8ed352 --- /dev/null +++ b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_ComputedJump.cs @@ -0,0 +1,46 @@ +using Newtonsoft.Json; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.Kismet.Bytecode.Expressions +{ + /// + /// A single Kismet bytecode instruction, corresponding to the instruction. + /// + public class EX_ComputedJump : KismetExpression + { + /// + /// The token of this expression. + /// + public override EExprToken Token { get { return EExprToken.EX_ComputedJump; } } + + /// + /// An integer expression corresponding to the offset to jump to. + /// + [JsonProperty] + public KismetExpression CodeOffsetExpression; + + public EX_ComputedJump() + { + + } + + /// + /// Reads out the expression from a BinaryReader. + /// + /// The BinaryReader to read from. + public override void Read(AssetBinaryReader reader) + { + CodeOffsetExpression = ExpressionSerializer.ReadExpression(reader); + } + + /// + /// Writes the expression to a BinaryWriter. + /// + /// The BinaryWriter to write from. + /// The iCode offset of the data that was written. + public override int Write(AssetBinaryWriter writer) + { + return ExpressionSerializer.WriteExpression(CodeOffsetExpression, writer); + } + } +} diff --git a/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_Context.cs b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_Context.cs new file mode 100644 index 0000000..4cdb788 --- /dev/null +++ b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_Context.cs @@ -0,0 +1,72 @@ +using Newtonsoft.Json; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.Kismet.Bytecode.Expressions +{ + /// + /// A single Kismet bytecode instruction, corresponding to the instruction. + /// + public class EX_Context : KismetExpression + { + /// + /// The token of this expression. + /// + public override EExprToken Token { get { return EExprToken.EX_Context; } } + + /// + /// Object expression. + /// + [JsonProperty] + public KismetExpression ObjectExpression; + + /// + /// Code offset for NULL expressions. + /// + [JsonProperty] + public uint Offset; + + /// + /// Property corresponding to the r-value data, in case the l-value needs to be mem-zero'd. FField* + /// + [JsonProperty] + public KismetPropertyPointer RValuePointer; + + /// + /// Context expression. + /// + [JsonProperty] + public KismetExpression ContextExpression; + + public EX_Context() + { + + } + + /// + /// Reads out the expression from a BinaryReader. + /// + /// The BinaryReader to read from. + public override void Read(AssetBinaryReader reader) + { + ObjectExpression = ExpressionSerializer.ReadExpression(reader); + Offset = reader.ReadUInt32(); + RValuePointer = reader.XFER_PROP_POINTER(); + ContextExpression = ExpressionSerializer.ReadExpression(reader); + } + + /// + /// Writes the expression to a BinaryWriter. + /// + /// The BinaryWriter to write from. + /// The iCode offset of the data that was written. + public override int Write(AssetBinaryWriter writer) + { + int offset = 0; + offset += ExpressionSerializer.WriteExpression(ObjectExpression, writer); + writer.Write(Offset); offset += sizeof(uint); + offset += writer.XFER_PROP_POINTER(RValuePointer); + offset += ExpressionSerializer.WriteExpression(ContextExpression, writer); + return offset; + } + } +} diff --git a/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_Context_FailSilent.cs b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_Context_FailSilent.cs new file mode 100644 index 0000000..d83d312 --- /dev/null +++ b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_Context_FailSilent.cs @@ -0,0 +1,37 @@ +namespace UAssetAPI.Kismet.Bytecode.Expressions +{ + /// + /// A single Kismet bytecode instruction, corresponding to the instruction. + /// + public class EX_Context_FailSilent : EX_Context + { + /// + /// The token of this expression. + /// + public override EExprToken Token { get { return EExprToken.EX_Context_FailSilent; } } + + public EX_Context_FailSilent() + { + + } + + /// + /// Reads out the expression from a BinaryReader. + /// + /// The BinaryReader to read from. + public override void Read(AssetBinaryReader reader) + { + base.Read(reader); + } + + /// + /// Writes the expression to a BinaryWriter. + /// + /// The BinaryWriter to write from. + /// The iCode offset of the data that was written. + public override int Write(AssetBinaryWriter writer) + { + return base.Write(writer); + } + } +} diff --git a/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_CrossInterfaceCast.cs b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_CrossInterfaceCast.cs new file mode 100644 index 0000000..70451c4 --- /dev/null +++ b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_CrossInterfaceCast.cs @@ -0,0 +1,56 @@ +using Newtonsoft.Json; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.Kismet.Bytecode.Expressions +{ + /// + /// A single Kismet bytecode instruction, corresponding to the instruction. + /// + public class EX_CrossInterfaceCast : KismetExpression + { + /// + /// The token of this expression. + /// + public override EExprToken Token { get { return EExprToken.EX_CrossInterfaceCast; } } + + /// + /// A pointer to the interface class to convert to. + /// + [JsonProperty] + public FPackageIndex ClassPtr; + + /// + /// The target of this expression. + /// + [JsonProperty] + public KismetExpression Target; + + public EX_CrossInterfaceCast() + { + + } + + /// + /// Reads out the expression from a BinaryReader. + /// + /// The BinaryReader to read from. + public override void Read(AssetBinaryReader reader) + { + ClassPtr = reader.XFER_OBJECT_POINTER(); + Target = ExpressionSerializer.ReadExpression(reader); + } + + /// + /// Writes the expression to a BinaryWriter. + /// + /// The BinaryWriter to write from. + /// The iCode offset of the data that was written. + public override int Write(AssetBinaryWriter writer) + { + int offset = 0; + offset += writer.XFER_OBJECT_POINTER(ClassPtr); + offset += ExpressionSerializer.WriteExpression(Target, writer); + return offset; + } + } +} diff --git a/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_DefaultVariable.cs b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_DefaultVariable.cs new file mode 100644 index 0000000..12bf8e8 --- /dev/null +++ b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_DefaultVariable.cs @@ -0,0 +1,46 @@ +using Newtonsoft.Json; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.Kismet.Bytecode.Expressions +{ + /// + /// A single Kismet bytecode instruction, corresponding to the instruction. + /// + public class EX_DefaultVariable : KismetExpression + { + /// + /// The token of this expression. + /// + public override EExprToken Token { get { return EExprToken.EX_DefaultVariable; } } + + /// + /// A pointer to the variable in question. + /// + [JsonProperty] + public KismetPropertyPointer Variable; + + public EX_DefaultVariable() + { + + } + + /// + /// Reads out the expression from a BinaryReader. + /// + /// The BinaryReader to read from. + public override void Read(AssetBinaryReader reader) + { + Variable = reader.XFER_PROP_POINTER(); + } + + /// + /// Writes the expression to a BinaryWriter. + /// + /// The BinaryWriter to write from. + /// The iCode offset of the data that was written. + public override int Write(AssetBinaryWriter writer) + { + return writer.XFER_PROP_POINTER(Variable); + } + } +} diff --git a/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_DeprecatedOp4A.cs b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_DeprecatedOp4A.cs new file mode 100644 index 0000000..86a50ef --- /dev/null +++ b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_DeprecatedOp4A.cs @@ -0,0 +1,37 @@ +namespace UAssetAPI.Kismet.Bytecode.Expressions +{ + /// + /// A single Kismet bytecode instruction, corresponding to the instruction. + /// + public class EX_DeprecatedOp4A : KismetExpression + { + /// + /// The token of this expression. + /// + public override EExprToken Token { get { return EExprToken.EX_DeprecatedOp4A; } } + + public EX_DeprecatedOp4A() + { + + } + + /// + /// Reads out the expression from a BinaryReader. + /// + /// The BinaryReader to read from. + public override void Read(AssetBinaryReader reader) + { + + } + + /// + /// Writes the expression to a BinaryWriter. + /// + /// The BinaryWriter to write from. + /// The iCode offset of the data that was written. + public override int Write(AssetBinaryWriter writer) + { + return 0; + } + } +} diff --git a/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_DynamicCast.cs b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_DynamicCast.cs new file mode 100644 index 0000000..9b0a0e4 --- /dev/null +++ b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_DynamicCast.cs @@ -0,0 +1,56 @@ +using Newtonsoft.Json; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.Kismet.Bytecode.Expressions +{ + /// + /// A single Kismet bytecode instruction, corresponding to the instruction. + /// + public class EX_DynamicCast : KismetExpression + { + /// + /// The token of this expression. + /// + public override EExprToken Token { get { return EExprToken.EX_DynamicCast; } } + + /// + /// A pointer to the relevant class (UClass*). + /// + [JsonProperty] + public FPackageIndex ClassPtr; + + /// + /// The target expression. + /// + [JsonProperty] + public KismetExpression TargetExpression; + + public EX_DynamicCast() + { + + } + + /// + /// Reads out the expression from a BinaryReader. + /// + /// The BinaryReader to read from. + public override void Read(AssetBinaryReader reader) + { + ClassPtr = reader.XFER_OBJECT_POINTER(); + TargetExpression = ExpressionSerializer.ReadExpression(reader); + } + + /// + /// Writes the expression to a BinaryWriter. + /// + /// The BinaryWriter to write from. + /// The iCode offset of the data that was written. + public override int Write(AssetBinaryWriter writer) + { + int offset = 0; + offset += writer.XFER_OBJECT_POINTER(ClassPtr); + offset += ExpressionSerializer.WriteExpression(TargetExpression, writer); + return offset; + } + } +} diff --git a/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_EndArray.cs b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_EndArray.cs new file mode 100644 index 0000000..fee1622 --- /dev/null +++ b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_EndArray.cs @@ -0,0 +1,37 @@ +namespace UAssetAPI.Kismet.Bytecode.Expressions +{ + /// + /// A single Kismet bytecode instruction, corresponding to the instruction. + /// + public class EX_EndArray : KismetExpression + { + /// + /// The token of this expression. + /// + public override EExprToken Token { get { return EExprToken.EX_EndArray; } } + + public EX_EndArray() + { + + } + + /// + /// Reads out the expression from a BinaryReader. + /// + /// The BinaryReader to read from. + public override void Read(AssetBinaryReader reader) + { + + } + + /// + /// Writes the expression to a BinaryWriter. + /// + /// The BinaryWriter to write from. + /// The iCode offset of the data that was written. + public override int Write(AssetBinaryWriter writer) + { + return 0; + } + } +} diff --git a/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_EndArrayConst.cs b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_EndArrayConst.cs new file mode 100644 index 0000000..220de7d --- /dev/null +++ b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_EndArrayConst.cs @@ -0,0 +1,37 @@ +namespace UAssetAPI.Kismet.Bytecode.Expressions +{ + /// + /// A single Kismet bytecode instruction, corresponding to the instruction. + /// + public class EX_EndArrayConst : KismetExpression + { + /// + /// The token of this expression. + /// + public override EExprToken Token { get { return EExprToken.EX_EndArrayConst; } } + + public EX_EndArrayConst() + { + + } + + /// + /// Reads out the expression from a BinaryReader. + /// + /// The BinaryReader to read from. + public override void Read(AssetBinaryReader reader) + { + + } + + /// + /// Writes the expression to a BinaryWriter. + /// + /// The BinaryWriter to write from. + /// The iCode offset of the data that was written. + public override int Write(AssetBinaryWriter writer) + { + return 0; + } + } +} diff --git a/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_EndFunctionParms.cs b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_EndFunctionParms.cs new file mode 100644 index 0000000..a134ba4 --- /dev/null +++ b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_EndFunctionParms.cs @@ -0,0 +1,37 @@ +namespace UAssetAPI.Kismet.Bytecode.Expressions +{ + /// + /// A single Kismet bytecode instruction, corresponding to the instruction. + /// + public class EX_EndFunctionParms : KismetExpression + { + /// + /// The token of this expression. + /// + public override EExprToken Token { get { return EExprToken.EX_EndFunctionParms; } } + + public EX_EndFunctionParms() + { + + } + + /// + /// Reads out the expression from a BinaryReader. + /// + /// The BinaryReader to read from. + public override void Read(AssetBinaryReader reader) + { + + } + + /// + /// Writes the expression to a BinaryWriter. + /// + /// The BinaryWriter to write from. + /// The iCode offset of the data that was written. + public override int Write(AssetBinaryWriter writer) + { + return 0; + } + } +} diff --git a/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_EndMap.cs b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_EndMap.cs new file mode 100644 index 0000000..ff1f757 --- /dev/null +++ b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_EndMap.cs @@ -0,0 +1,37 @@ +namespace UAssetAPI.Kismet.Bytecode.Expressions +{ + /// + /// A single Kismet bytecode instruction, corresponding to the instruction. + /// + public class EX_EndMap : KismetExpression + { + /// + /// The token of this expression. + /// + public override EExprToken Token { get { return EExprToken.EX_EndMap; } } + + public EX_EndMap() + { + + } + + /// + /// Reads out the expression from a BinaryReader. + /// + /// The BinaryReader to read from. + public override void Read(AssetBinaryReader reader) + { + + } + + /// + /// Writes the expression to a BinaryWriter. + /// + /// The BinaryWriter to write from. + /// The iCode offset of the data that was written. + public override int Write(AssetBinaryWriter writer) + { + return 0; + } + } +} diff --git a/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_EndMapConst.cs b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_EndMapConst.cs new file mode 100644 index 0000000..8eb5ab6 --- /dev/null +++ b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_EndMapConst.cs @@ -0,0 +1,37 @@ +namespace UAssetAPI.Kismet.Bytecode.Expressions +{ + /// + /// A single Kismet bytecode instruction, corresponding to the instruction. + /// + public class EX_EndMapConst : KismetExpression + { + /// + /// The token of this expression. + /// + public override EExprToken Token { get { return EExprToken.EX_EndMapConst; } } + + public EX_EndMapConst() + { + + } + + /// + /// Reads out the expression from a BinaryReader. + /// + /// The BinaryReader to read from. + public override void Read(AssetBinaryReader reader) + { + + } + + /// + /// Writes the expression to a BinaryWriter. + /// + /// The BinaryWriter to write from. + /// The iCode offset of the data that was written. + public override int Write(AssetBinaryWriter writer) + { + return 0; + } + } +} diff --git a/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_EndOfScript.cs b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_EndOfScript.cs new file mode 100644 index 0000000..3b3c75b --- /dev/null +++ b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_EndOfScript.cs @@ -0,0 +1,37 @@ +namespace UAssetAPI.Kismet.Bytecode.Expressions +{ + /// + /// A single Kismet bytecode instruction, corresponding to the instruction. + /// + public class EX_EndOfScript : KismetExpression + { + /// + /// The token of this expression. + /// + public override EExprToken Token { get { return EExprToken.EX_EndOfScript; } } + + public EX_EndOfScript() + { + + } + + /// + /// Reads out the expression from a BinaryReader. + /// + /// The BinaryReader to read from. + public override void Read(AssetBinaryReader reader) + { + + } + + /// + /// Writes the expression to a BinaryWriter. + /// + /// The BinaryWriter to write from. + /// The iCode offset of the data that was written. + public override int Write(AssetBinaryWriter writer) + { + return 0; + } + } +} diff --git a/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_EndParmValue.cs b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_EndParmValue.cs new file mode 100644 index 0000000..7ef94a8 --- /dev/null +++ b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_EndParmValue.cs @@ -0,0 +1,37 @@ +namespace UAssetAPI.Kismet.Bytecode.Expressions +{ + /// + /// A single Kismet bytecode instruction, corresponding to the instruction. + /// + public class EX_EndParmValue : KismetExpression + { + /// + /// The token of this expression. + /// + public override EExprToken Token { get { return EExprToken.EX_EndParmValue; } } + + public EX_EndParmValue() + { + + } + + /// + /// Reads out the expression from a BinaryReader. + /// + /// The BinaryReader to read from. + public override void Read(AssetBinaryReader reader) + { + + } + + /// + /// Writes the expression to a BinaryWriter. + /// + /// The BinaryWriter to write from. + /// The iCode offset of the data that was written. + public override int Write(AssetBinaryWriter writer) + { + return 0; + } + } +} diff --git a/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_EndSet.cs b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_EndSet.cs new file mode 100644 index 0000000..1487998 --- /dev/null +++ b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_EndSet.cs @@ -0,0 +1,37 @@ +namespace UAssetAPI.Kismet.Bytecode.Expressions +{ + /// + /// A single Kismet bytecode instruction, corresponding to the instruction. + /// + public class EX_EndSet : KismetExpression + { + /// + /// The token of this expression. + /// + public override EExprToken Token { get { return EExprToken.EX_EndSet; } } + + public EX_EndSet() + { + + } + + /// + /// Reads out the expression from a BinaryReader. + /// + /// The BinaryReader to read from. + public override void Read(AssetBinaryReader reader) + { + + } + + /// + /// Writes the expression to a BinaryWriter. + /// + /// The BinaryWriter to write from. + /// The iCode offset of the data that was written. + public override int Write(AssetBinaryWriter writer) + { + return 0; + } + } +} diff --git a/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_EndSetConst.cs b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_EndSetConst.cs new file mode 100644 index 0000000..cf5dfd2 --- /dev/null +++ b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_EndSetConst.cs @@ -0,0 +1,37 @@ +namespace UAssetAPI.Kismet.Bytecode.Expressions +{ + /// + /// A single Kismet bytecode instruction, corresponding to the instruction. + /// + public class EX_EndSetConst : KismetExpression + { + /// + /// The token of this expression. + /// + public override EExprToken Token { get { return EExprToken.EX_EndSetConst; } } + + public EX_EndSetConst() + { + + } + + /// + /// Reads out the expression from a BinaryReader. + /// + /// The BinaryReader to read from. + public override void Read(AssetBinaryReader reader) + { + + } + + /// + /// Writes the expression to a BinaryWriter. + /// + /// The BinaryWriter to write from. + /// The iCode offset of the data that was written. + public override int Write(AssetBinaryWriter writer) + { + return 0; + } + } +} diff --git a/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_EndStructConst.cs b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_EndStructConst.cs new file mode 100644 index 0000000..aaaaa06 --- /dev/null +++ b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_EndStructConst.cs @@ -0,0 +1,37 @@ +namespace UAssetAPI.Kismet.Bytecode.Expressions +{ + /// + /// A single Kismet bytecode instruction, corresponding to the instruction. + /// + public class EX_EndStructConst : KismetExpression + { + /// + /// The token of this expression. + /// + public override EExprToken Token { get { return EExprToken.EX_EndStructConst; } } + + public EX_EndStructConst() + { + + } + + /// + /// Reads out the expression from a BinaryReader. + /// + /// The BinaryReader to read from. + public override void Read(AssetBinaryReader reader) + { + + } + + /// + /// Writes the expression to a BinaryWriter. + /// + /// The BinaryWriter to write from. + /// The iCode offset of the data that was written. + public override int Write(AssetBinaryWriter writer) + { + return 0; + } + } +} diff --git a/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_False.cs b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_False.cs new file mode 100644 index 0000000..9cfdc46 --- /dev/null +++ b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_False.cs @@ -0,0 +1,37 @@ +namespace UAssetAPI.Kismet.Bytecode.Expressions +{ + /// + /// A single Kismet bytecode instruction, corresponding to the instruction. + /// + public class EX_False : KismetExpression + { + /// + /// The token of this expression. + /// + public override EExprToken Token { get { return EExprToken.EX_False; } } + + public EX_False() + { + + } + + /// + /// Reads out the expression from a BinaryReader. + /// + /// The BinaryReader to read from. + public override void Read(AssetBinaryReader reader) + { + + } + + /// + /// Writes the expression to a BinaryWriter. + /// + /// The BinaryWriter to write from. + /// The iCode offset of the data that was written. + public override int Write(AssetBinaryWriter writer) + { + return 0; + } + } +} diff --git a/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_FieldPathConst.cs b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_FieldPathConst.cs new file mode 100644 index 0000000..f30357d --- /dev/null +++ b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_FieldPathConst.cs @@ -0,0 +1,37 @@ +namespace UAssetAPI.Kismet.Bytecode.Expressions +{ + /// + /// A single Kismet bytecode instruction, corresponding to the instruction. + /// + public class EX_FieldPathConst : KismetExpression + { + /// + /// The token of this expression. + /// + public override EExprToken Token { get { return EExprToken.EX_FieldPathConst; } } + + public EX_FieldPathConst() + { + + } + + /// + /// Reads out the expression from a BinaryReader. + /// + /// The BinaryReader to read from. + public override void Read(AssetBinaryReader reader) + { + Value = ExpressionSerializer.ReadExpression(reader); + } + + /// + /// Writes the expression to a BinaryWriter. + /// + /// The BinaryWriter to write from. + /// The iCode offset of the data that was written. + public override int Write(AssetBinaryWriter writer) + { + return ExpressionSerializer.WriteExpression(Value, writer); + } + } +} diff --git a/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_FinalFunction.cs b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_FinalFunction.cs new file mode 100644 index 0000000..529035c --- /dev/null +++ b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_FinalFunction.cs @@ -0,0 +1,63 @@ +using Newtonsoft.Json; +using System.Collections.Generic; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.Kismet.Bytecode.Expressions +{ + /// + /// A single Kismet bytecode instruction, corresponding to the instruction. + /// + public class EX_FinalFunction : KismetExpression + { + /// + /// The token of this expression. + /// + public override EExprToken Token { get { return EExprToken.EX_FinalFunction; } } + + /// + /// Stack node. + /// + [JsonProperty] + public FPackageIndex StackNode; + + /// + /// List of parameters for this function. + /// + [JsonProperty] + public KismetExpression[] Parameters; + + public EX_FinalFunction() + { + + } + + /// + /// Reads out the expression from a BinaryReader. + /// + /// The BinaryReader to read from. + public override void Read(AssetBinaryReader reader) + { + StackNode = reader.XFER_FUNC_POINTER(); + + Parameters = reader.ReadExpressionArray(EExprToken.EX_EndFunctionParms); + } + + /// + /// Writes the expression to a BinaryWriter. + /// + /// The BinaryWriter to write from. + /// The iCode offset of the data that was written. + public override int Write(AssetBinaryWriter writer) + { + int offset = 0; + offset += writer.XFER_FUNC_POINTER(StackNode); + + for (int i = 0; i < Parameters.Length; i++) + { + offset += ExpressionSerializer.WriteExpression(Parameters[i], writer); + } + offset += ExpressionSerializer.WriteExpression(new EX_EndFunctionParms(), writer); + return offset; + } + } +} diff --git a/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_FloatConst.cs b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_FloatConst.cs new file mode 100644 index 0000000..f5c2e48 --- /dev/null +++ b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_FloatConst.cs @@ -0,0 +1,49 @@ +using Newtonsoft.Json; +using UAssetAPI.JSON; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.Kismet.Bytecode.Expressions +{ + /// + /// A single Kismet bytecode instruction, corresponding to the instruction. + /// + public class EX_FloatConst : KismetExpression + { + /// + /// The token of this expression. + /// + public override EExprToken Token { get { return EExprToken.EX_FloatConst; } } + + /// + /// The value of this float constant expression. + /// + [JsonProperty] + [JsonConverter(typeof(FSignedZeroJsonConverter))] + public float Value; + + public EX_FloatConst() + { + + } + + /// + /// Reads out the expression from a BinaryReader. + /// + /// The BinaryReader to read from. + public override void Read(AssetBinaryReader reader) + { + Value = reader.ReadSingle(); + } + + /// + /// Writes the expression to a BinaryWriter. + /// + /// The BinaryWriter to write from. + /// The iCode offset of the data that was written. + public override int Write(AssetBinaryWriter writer) + { + writer.Write(Value); + return sizeof(float); + } + } +} diff --git a/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_InstanceDelegate.cs b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_InstanceDelegate.cs new file mode 100644 index 0000000..870f028 --- /dev/null +++ b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_InstanceDelegate.cs @@ -0,0 +1,46 @@ +using Newtonsoft.Json; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.Kismet.Bytecode.Expressions +{ + /// + /// A single Kismet bytecode instruction, corresponding to the instruction. + /// + public class EX_InstanceDelegate : KismetExpression + { + /// + /// The token of this expression. + /// + public override EExprToken Token { get { return EExprToken.EX_InstanceDelegate; } } + + /// + /// The name of the function assigned to the delegate. + /// + [JsonProperty] + public FName FunctionName; + + public EX_InstanceDelegate() + { + + } + + /// + /// Reads out the expression from a BinaryReader. + /// + /// The BinaryReader to read from. + public override void Read(AssetBinaryReader reader) + { + FunctionName = reader.XFER_FUNC_NAME(); + } + + /// + /// Writes the expression to a BinaryWriter. + /// + /// The BinaryWriter to write from. + /// The iCode offset of the data that was written. + public override int Write(AssetBinaryWriter writer) + { + return writer.XFER_FUNC_NAME(FunctionName); + } + } +} diff --git a/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_InstanceVariable.cs b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_InstanceVariable.cs new file mode 100644 index 0000000..f8cf310 --- /dev/null +++ b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_InstanceVariable.cs @@ -0,0 +1,46 @@ +using Newtonsoft.Json; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.Kismet.Bytecode.Expressions +{ + /// + /// A single Kismet bytecode instruction, corresponding to the instruction. + /// + public class EX_InstanceVariable : KismetExpression + { + /// + /// The token of this expression. + /// + public override EExprToken Token { get { return EExprToken.EX_InstanceVariable; } } + + /// + /// A pointer to the variable in question. + /// + [JsonProperty] + public KismetPropertyPointer Variable; + + public EX_InstanceVariable() + { + + } + + /// + /// Reads out the expression from a BinaryReader. + /// + /// The BinaryReader to read from. + public override void Read(AssetBinaryReader reader) + { + Variable = reader.XFER_PROP_POINTER(); + } + + /// + /// Writes the expression to a BinaryWriter. + /// + /// The BinaryWriter to write from. + /// The iCode offset of the data that was written. + public override int Write(AssetBinaryWriter writer) + { + return writer.XFER_PROP_POINTER(Variable); + } + } +} diff --git a/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_InstrumentationEvent.cs b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_InstrumentationEvent.cs new file mode 100644 index 0000000..1a0b5e0 --- /dev/null +++ b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_InstrumentationEvent.cs @@ -0,0 +1,58 @@ +using Newtonsoft.Json; +using System; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.Kismet.Bytecode.Expressions +{ + + /// + /// A single Kismet bytecode instruction, corresponding to the instruction. + /// + public class EX_InstrumentationEvent : KismetExpression + { + /// + /// The token of this expression. + /// + public override EExprToken Token { get { return EExprToken.EX_InstrumentationEvent; } } + + [JsonProperty] + public EScriptInstrumentationType EventType; + [JsonProperty] + public FName EventName; + + public EX_InstrumentationEvent() + { + + } + + /// + /// Reads out the expression from a BinaryReader. + /// + /// The BinaryReader to read from. + public override void Read(AssetBinaryReader reader) + { + EventType = (EScriptInstrumentationType)reader.ReadByte(); + + if (EventType.Equals(EScriptInstrumentationType.InlineEvent)) + { + EventName = reader.XFER_FUNC_NAME(); + } + } + + /// + /// Writes the expression to a BinaryWriter. + /// + /// The BinaryWriter to write from. + /// The iCode offset of the data that was written. + public override int Write(AssetBinaryWriter writer) + { + writer.Write((byte)EventType); + if (EventType.Equals(EScriptInstrumentationType.InlineEvent)) { + writer.XFER_FUNC_NAME(EventName); + return 1 + 2 * sizeof(int); + } else { + return 1; + } + } + } +} diff --git a/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_Int64Const.cs b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_Int64Const.cs new file mode 100644 index 0000000..51d325e --- /dev/null +++ b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_Int64Const.cs @@ -0,0 +1,38 @@ +namespace UAssetAPI.Kismet.Bytecode.Expressions +{ + /// + /// A single Kismet bytecode instruction, corresponding to the instruction. + /// + public class EX_Int64Const : KismetExpression + { + /// + /// The token of this expression. + /// + public override EExprToken Token { get { return EExprToken.EX_Int64Const; } } + + public EX_Int64Const() + { + + } + + /// + /// Reads out the expression from a BinaryReader. + /// + /// The BinaryReader to read from. + public override void Read(AssetBinaryReader reader) + { + Value = reader.ReadInt64(); + } + + /// + /// Writes the expression to a BinaryWriter. + /// + /// The BinaryWriter to write from. + /// The iCode offset of the data that was written. + public override int Write(AssetBinaryWriter writer) + { + writer.Write(Value); + return sizeof(long); + } + } +} diff --git a/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_IntConst.cs b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_IntConst.cs new file mode 100644 index 0000000..f5740be --- /dev/null +++ b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_IntConst.cs @@ -0,0 +1,38 @@ +namespace UAssetAPI.Kismet.Bytecode.Expressions +{ + /// + /// A single Kismet bytecode instruction, corresponding to the instruction. + /// + public class EX_IntConst : KismetExpression + { + /// + /// The token of this expression. + /// + public override EExprToken Token { get { return EExprToken.EX_IntConst; } } + + public EX_IntConst() + { + + } + + /// + /// Reads out the expression from a BinaryReader. + /// + /// The BinaryReader to read from. + public override void Read(AssetBinaryReader reader) + { + Value = reader.ReadInt32(); + } + + /// + /// Writes the expression to a BinaryWriter. + /// + /// The BinaryWriter to write from. + /// The iCode offset of the data that was written. + public override int Write(AssetBinaryWriter writer) + { + writer.Write(Value); + return sizeof(int); + } + } +} diff --git a/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_IntConstByte.cs b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_IntConstByte.cs new file mode 100644 index 0000000..95bf51c --- /dev/null +++ b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_IntConstByte.cs @@ -0,0 +1,38 @@ +namespace UAssetAPI.Kismet.Bytecode.Expressions +{ + /// + /// A single Kismet bytecode instruction, corresponding to the instruction. + /// + public class EX_IntConstByte : KismetExpression + { + /// + /// The token of this expression. + /// + public override EExprToken Token { get { return EExprToken.EX_IntConstByte; } } + + public EX_IntConstByte() + { + + } + + /// + /// Reads out the expression from a BinaryReader. + /// + /// The BinaryReader to read from. + public override void Read(AssetBinaryReader reader) + { + Value = reader.ReadByte(); + } + + /// + /// Writes the expression to a BinaryWriter. + /// + /// The BinaryWriter to write from. + /// The iCode offset of the data that was written. + public override int Write(AssetBinaryWriter writer) + { + writer.Write(Value); + return sizeof(byte); + } + } +} diff --git a/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_IntOne.cs b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_IntOne.cs new file mode 100644 index 0000000..cde3ecf --- /dev/null +++ b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_IntOne.cs @@ -0,0 +1,37 @@ +namespace UAssetAPI.Kismet.Bytecode.Expressions +{ + /// + /// A single Kismet bytecode instruction, corresponding to the instruction. + /// + public class EX_IntOne : KismetExpression + { + /// + /// The token of this expression. + /// + public override EExprToken Token { get { return EExprToken.EX_IntOne; } } + + public EX_IntOne() + { + + } + + /// + /// Reads out the expression from a BinaryReader. + /// + /// The BinaryReader to read from. + public override void Read(AssetBinaryReader reader) + { + + } + + /// + /// Writes the expression to a BinaryWriter. + /// + /// The BinaryWriter to write from. + /// The iCode offset of the data that was written. + public override int Write(AssetBinaryWriter writer) + { + return 0; + } + } +} diff --git a/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_IntZero.cs b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_IntZero.cs new file mode 100644 index 0000000..95cc74f --- /dev/null +++ b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_IntZero.cs @@ -0,0 +1,37 @@ +namespace UAssetAPI.Kismet.Bytecode.Expressions +{ + /// + /// A single Kismet bytecode instruction, corresponding to the instruction. + /// + public class EX_IntZero : KismetExpression + { + /// + /// The token of this expression. + /// + public override EExprToken Token { get { return EExprToken.EX_IntZero; } } + + public EX_IntZero() + { + + } + + /// + /// Reads out the expression from a BinaryReader. + /// + /// The BinaryReader to read from. + public override void Read(AssetBinaryReader reader) + { + + } + + /// + /// Writes the expression to a BinaryWriter. + /// + /// The BinaryWriter to write from. + /// The iCode offset of the data that was written. + public override int Write(AssetBinaryWriter writer) + { + return 0; + } + } +} diff --git a/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_InterfaceContext.cs b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_InterfaceContext.cs new file mode 100644 index 0000000..20535b7 --- /dev/null +++ b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_InterfaceContext.cs @@ -0,0 +1,46 @@ +using Newtonsoft.Json; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.Kismet.Bytecode.Expressions +{ + /// + /// A single Kismet bytecode instruction, corresponding to the instruction. + /// + public class EX_InterfaceContext : KismetExpression + { + /// + /// The token of this expression. + /// + public override EExprToken Token { get { return EExprToken.EX_InterfaceContext; } } + + /// + /// Interface value. + /// + [JsonProperty] + public KismetExpression InterfaceValue; + + public EX_InterfaceContext() + { + + } + + /// + /// Reads out the expression from a BinaryReader. + /// + /// The BinaryReader to read from. + public override void Read(AssetBinaryReader reader) + { + InterfaceValue = ExpressionSerializer.ReadExpression(reader); + } + + /// + /// Writes the expression to a BinaryWriter. + /// + /// The BinaryWriter to write from. + /// The iCode offset of the data that was written. + public override int Write(AssetBinaryWriter writer) + { + return ExpressionSerializer.WriteExpression(InterfaceValue, writer); + } + } +} diff --git a/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_InterfaceToObjCast.cs b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_InterfaceToObjCast.cs new file mode 100644 index 0000000..2e1f3a0 --- /dev/null +++ b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_InterfaceToObjCast.cs @@ -0,0 +1,56 @@ +using Newtonsoft.Json; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.Kismet.Bytecode.Expressions +{ + /// + /// A single Kismet bytecode instruction, corresponding to the instruction. + /// + public class EX_InterfaceToObjCast : KismetExpression + { + /// + /// The token of this expression. + /// + public override EExprToken Token { get { return EExprToken.EX_InterfaceToObjCast; } } + + /// + /// The interface class to convert to. + /// + [JsonProperty] + public FPackageIndex ClassPtr; + + /// + /// The target of this expression. + /// + [JsonProperty] + public KismetExpression Target; + + public EX_InterfaceToObjCast() + { + + } + + /// + /// Reads out the expression from a BinaryReader. + /// + /// The BinaryReader to read from. + public override void Read(AssetBinaryReader reader) + { + ClassPtr = reader.XFER_OBJECT_POINTER(); + Target = ExpressionSerializer.ReadExpression(reader); + } + + /// + /// Writes the expression to a BinaryWriter. + /// + /// The BinaryWriter to write from. + /// The iCode offset of the data that was written. + public override int Write(AssetBinaryWriter writer) + { + int offset = 0; + offset += writer.XFER_OBJECT_POINTER(ClassPtr); + offset += ExpressionSerializer.WriteExpression(Target, writer); + return offset; + } + } +} diff --git a/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_Jump.cs b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_Jump.cs new file mode 100644 index 0000000..54def3e --- /dev/null +++ b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_Jump.cs @@ -0,0 +1,47 @@ +using Newtonsoft.Json; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.Kismet.Bytecode.Expressions +{ + /// + /// A single Kismet bytecode instruction, corresponding to the instruction. + /// + public class EX_Jump : KismetExpression + { + /// + /// The token of this expression. + /// + public override EExprToken Token { get { return EExprToken.EX_Jump; } } + + /// + /// The offset to jump to. + /// + [JsonProperty] + public uint CodeOffset; + + public EX_Jump() + { + + } + + /// + /// Reads out the expression from a BinaryReader. + /// + /// The BinaryReader to read from. + public override void Read(AssetBinaryReader reader) + { + CodeOffset = reader.ReadUInt32(); + } + + /// + /// Writes the expression to a BinaryWriter. + /// + /// The BinaryWriter to write from. + /// The iCode offset of the data that was written. + public override int Write(AssetBinaryWriter writer) + { + writer.Write(CodeOffset); + return sizeof(uint); + } + } +} diff --git a/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_JumpIfNot.cs b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_JumpIfNot.cs new file mode 100644 index 0000000..d4c81af --- /dev/null +++ b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_JumpIfNot.cs @@ -0,0 +1,57 @@ +using Newtonsoft.Json; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.Kismet.Bytecode.Expressions +{ + /// + /// A single Kismet bytecode instruction, corresponding to the instruction. + /// Conditional equivalent of the expression. + /// + public class EX_JumpIfNot : KismetExpression + { + /// + /// The token of this expression. + /// + public override EExprToken Token { get { return EExprToken.EX_JumpIfNot; } } + + /// + /// The offset to jump to if the provided expression evaluates to false. + /// + [JsonProperty] + public uint CodeOffset; + + /// + /// Expression to evaluate to determine whether or not a jump should be performed. + /// + [JsonProperty] + public KismetExpression BooleanExpression; + + public EX_JumpIfNot() + { + + } + + /// + /// Reads out the expression from a BinaryReader. + /// + /// The BinaryReader to read from. + public override void Read(AssetBinaryReader reader) + { + CodeOffset = reader.ReadUInt32(); + BooleanExpression = ExpressionSerializer.ReadExpression(reader); + } + + /// + /// Writes the expression to a BinaryWriter. + /// + /// The BinaryWriter to write from. + /// The iCode offset of the data that was written. + public override int Write(AssetBinaryWriter writer) + { + int offset = 0; + writer.Write(CodeOffset); offset += sizeof(uint); + offset += ExpressionSerializer.WriteExpression(BooleanExpression, writer); + return offset; + } + } +} diff --git a/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_Let.cs b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_Let.cs new file mode 100644 index 0000000..8be8978 --- /dev/null +++ b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_Let.cs @@ -0,0 +1,56 @@ +using Newtonsoft.Json; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.Kismet.Bytecode.Expressions +{ + /// + /// A single Kismet bytecode instruction, corresponding to the instruction. + /// + public class EX_Let : KismetExpression + { + /// + /// The token of this expression. + /// + public override EExprToken Token { get { return EExprToken.EX_Let; } } + + /// + /// A pointer to the variable. + /// + [JsonProperty] + public KismetPropertyPointer Value; + [JsonProperty] + public KismetExpression Variable; + [JsonProperty] + public KismetExpression Expression; + + public EX_Let() + { + + } + + /// + /// Reads out the expression from a BinaryReader. + /// + /// The BinaryReader to read from. + public override void Read(AssetBinaryReader reader) + { + Value = reader.XFER_PROP_POINTER(); + Variable = ExpressionSerializer.ReadExpression(reader); + Expression = ExpressionSerializer.ReadExpression(reader); + } + + /// + /// Writes the expression to a BinaryWriter. + /// + /// The BinaryWriter to write from. + /// The iCode offset of the data that was written. + public override int Write(AssetBinaryWriter writer) + { + int offset = 0; + offset += writer.XFER_PROP_POINTER(Value); + offset += ExpressionSerializer.WriteExpression(Variable, writer); + offset += ExpressionSerializer.WriteExpression(Expression, writer); + return offset; + } + } +} diff --git a/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_LetBool.cs b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_LetBool.cs new file mode 100644 index 0000000..e2dd414 --- /dev/null +++ b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_LetBool.cs @@ -0,0 +1,55 @@ +using Newtonsoft.Json; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.Kismet.Bytecode.Expressions +{ + /// + /// A single Kismet bytecode instruction, corresponding to the instruction. + /// + public class EX_LetBool : KismetExpression + { + /// + /// The token of this expression. + /// + public override EExprToken Token { get { return EExprToken.EX_LetBool; } } + + /// + /// Variable expression. + /// + [JsonProperty] + public KismetExpression VariableExpression; + + /// + /// Assignment expression. + /// + [JsonProperty] + public KismetExpression AssignmentExpression; + public EX_LetBool() + { + + } + + /// + /// Reads out the expression from a BinaryReader. + /// + /// The BinaryReader to read from. + public override void Read(AssetBinaryReader reader) + { + VariableExpression = ExpressionSerializer.ReadExpression(reader); + AssignmentExpression = ExpressionSerializer.ReadExpression(reader); + } + + /// + /// Writes the expression to a BinaryWriter. + /// + /// The BinaryWriter to write from. + /// The iCode offset of the data that was written. + public override int Write(AssetBinaryWriter writer) + { + int offset = 0; + offset += ExpressionSerializer.WriteExpression(VariableExpression, writer); + offset += ExpressionSerializer.WriteExpression(AssignmentExpression, writer); + return offset; + } + } +} diff --git a/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_LetDelegate.cs b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_LetDelegate.cs new file mode 100644 index 0000000..fd7c3f7 --- /dev/null +++ b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_LetDelegate.cs @@ -0,0 +1,56 @@ +using Newtonsoft.Json; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.Kismet.Bytecode.Expressions +{ + /// + /// A single Kismet bytecode instruction, corresponding to the instruction. + /// + public class EX_LetDelegate : KismetExpression + { + /// + /// The token of this expression. + /// + public override EExprToken Token { get { return EExprToken.EX_LetDelegate; } } + + /// + /// Variable expression. + /// + [JsonProperty] + public KismetExpression VariableExpression; + + /// + /// Assignment expression. + /// + [JsonProperty] + public KismetExpression AssignmentExpression; + + public EX_LetDelegate() + { + + } + + /// + /// Reads out the expression from a BinaryReader. + /// + /// The BinaryReader to read from. + public override void Read(AssetBinaryReader reader) + { + VariableExpression = ExpressionSerializer.ReadExpression(reader); + AssignmentExpression = ExpressionSerializer.ReadExpression(reader); + } + + /// + /// Writes the expression to a BinaryWriter. + /// + /// The BinaryWriter to write from. + /// The iCode offset of the data that was written. + public override int Write(AssetBinaryWriter writer) + { + int offset = 0; + offset += ExpressionSerializer.WriteExpression(VariableExpression, writer); + offset += ExpressionSerializer.WriteExpression(AssignmentExpression, writer); + return offset; + } + } +} diff --git a/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_LetMulticastDelegate.cs b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_LetMulticastDelegate.cs new file mode 100644 index 0000000..3caf2c7 --- /dev/null +++ b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_LetMulticastDelegate.cs @@ -0,0 +1,56 @@ +using Newtonsoft.Json; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.Kismet.Bytecode.Expressions +{ + /// + /// A single Kismet bytecode instruction, corresponding to the instruction. + /// + public class EX_LetMulticastDelegate : KismetExpression + { + /// + /// The token of this expression. + /// + public override EExprToken Token { get { return EExprToken.EX_LetMulticastDelegate; } } + + /// + /// Variable expression. + /// + [JsonProperty] + public KismetExpression VariableExpression; + + /// + /// Assignment expression. + /// + [JsonProperty] + public KismetExpression AssignmentExpression; + + public EX_LetMulticastDelegate() + { + + } + + /// + /// Reads out the expression from a BinaryReader. + /// + /// The BinaryReader to read from. + public override void Read(AssetBinaryReader reader) + { + VariableExpression = ExpressionSerializer.ReadExpression(reader); + AssignmentExpression = ExpressionSerializer.ReadExpression(reader); + } + + /// + /// Writes the expression to a BinaryWriter. + /// + /// The BinaryWriter to write from. + /// The iCode offset of the data that was written. + public override int Write(AssetBinaryWriter writer) + { + int offset = 0; + offset += ExpressionSerializer.WriteExpression(VariableExpression, writer); + offset += ExpressionSerializer.WriteExpression(AssignmentExpression, writer); + return offset; + } + } +} diff --git a/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_LetObj.cs b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_LetObj.cs new file mode 100644 index 0000000..d9e58c0 --- /dev/null +++ b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_LetObj.cs @@ -0,0 +1,56 @@ +using Newtonsoft.Json; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.Kismet.Bytecode.Expressions +{ + /// + /// A single Kismet bytecode instruction, corresponding to the instruction. + /// + public class EX_LetObj : KismetExpression + { + /// + /// The token of this expression. + /// + public override EExprToken Token { get { return EExprToken.EX_LetObj; } } + + /// + /// Variable expression. + /// + [JsonProperty] + public KismetExpression VariableExpression; + + /// + /// Assignment expression. + /// + [JsonProperty] + public KismetExpression AssignmentExpression; + + public EX_LetObj() + { + + } + + /// + /// Reads out the expression from a BinaryReader. + /// + /// The BinaryReader to read from. + public override void Read(AssetBinaryReader reader) + { + VariableExpression = ExpressionSerializer.ReadExpression(reader); + AssignmentExpression = ExpressionSerializer.ReadExpression(reader); + } + + /// + /// Writes the expression to a BinaryWriter. + /// + /// The BinaryWriter to write from. + /// The iCode offset of the data that was written. + public override int Write(AssetBinaryWriter writer) + { + int offset = 0; + offset += ExpressionSerializer.WriteExpression(VariableExpression, writer); + offset += ExpressionSerializer.WriteExpression(AssignmentExpression, writer); + return offset; + } + } +} diff --git a/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_LetValueOnPersistentFrame.cs b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_LetValueOnPersistentFrame.cs new file mode 100644 index 0000000..7ef0288 --- /dev/null +++ b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_LetValueOnPersistentFrame.cs @@ -0,0 +1,56 @@ +using Newtonsoft.Json; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.Kismet.Bytecode.Expressions +{ + /// + /// A single Kismet bytecode instruction, corresponding to the instruction. + /// + public class EX_LetValueOnPersistentFrame : KismetExpression + { + /// + /// The token of this expression. + /// + public override EExprToken Token { get { return EExprToken.EX_LetValueOnPersistentFrame; } } + + /// + /// Destination property pointer. + /// + [JsonProperty] + public KismetPropertyPointer DestinationProperty; + + /// + /// Assignment expression. + /// + [JsonProperty] + public KismetExpression AssignmentExpression; + + public EX_LetValueOnPersistentFrame() + { + + } + + /// + /// Reads out the expression from a BinaryReader. + /// + /// The BinaryReader to read from. + public override void Read(AssetBinaryReader reader) + { + DestinationProperty = reader.XFER_PROP_POINTER(); + AssignmentExpression = ExpressionSerializer.ReadExpression(reader); + } + + /// + /// Writes the expression to a BinaryWriter. + /// + /// The BinaryWriter to write from. + /// The iCode offset of the data that was written. + public override int Write(AssetBinaryWriter writer) + { + int offset = 0; + offset += writer.XFER_PROP_POINTER(DestinationProperty); + offset += ExpressionSerializer.WriteExpression(AssignmentExpression, writer); + return offset; + } + } +} diff --git a/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_LetWeakObjPtr.cs b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_LetWeakObjPtr.cs new file mode 100644 index 0000000..244890a --- /dev/null +++ b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_LetWeakObjPtr.cs @@ -0,0 +1,56 @@ +using Newtonsoft.Json; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.Kismet.Bytecode.Expressions +{ + /// + /// A single Kismet bytecode instruction, corresponding to the instruction. + /// + public class EX_LetWeakObjPtr : KismetExpression + { + /// + /// The token of this expression. + /// + public override EExprToken Token { get { return EExprToken.EX_LetWeakObjPtr; } } + + /// + /// Variable expression. + /// + [JsonProperty] + public KismetExpression VariableExpression; + + /// + /// Assignment expression. + /// + [JsonProperty] + public KismetExpression AssignmentExpression; + + public EX_LetWeakObjPtr() + { + + } + + /// + /// Reads out the expression from a BinaryReader. + /// + /// The BinaryReader to read from. + public override void Read(AssetBinaryReader reader) + { + VariableExpression = ExpressionSerializer.ReadExpression(reader); + AssignmentExpression = ExpressionSerializer.ReadExpression(reader); + } + + /// + /// Writes the expression to a BinaryWriter. + /// + /// The BinaryWriter to write from. + /// The iCode offset of the data that was written. + public override int Write(AssetBinaryWriter writer) + { + int offset = 0; + offset += ExpressionSerializer.WriteExpression(VariableExpression, writer); + offset += ExpressionSerializer.WriteExpression(AssignmentExpression, writer); + return offset; + } + } +} diff --git a/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_LocalFinalFunction.cs b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_LocalFinalFunction.cs new file mode 100644 index 0000000..d972a69 --- /dev/null +++ b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_LocalFinalFunction.cs @@ -0,0 +1,37 @@ +namespace UAssetAPI.Kismet.Bytecode.Expressions +{ + /// + /// A single Kismet bytecode instruction, corresponding to the instruction. + /// + public class EX_LocalFinalFunction : EX_FinalFunction + { + /// + /// The token of this expression. + /// + public override EExprToken Token { get { return EExprToken.EX_LocalFinalFunction; } } + + public EX_LocalFinalFunction() : base() + { + + } + + /// + /// Reads out the expression from a BinaryReader. + /// + /// The BinaryReader to read from. + public override void Read(AssetBinaryReader reader) + { + base.Read(reader); + } + + /// + /// Writes the expression to a BinaryWriter. + /// + /// The BinaryWriter to write from. + /// The iCode offset of the data that was written. + public override int Write(AssetBinaryWriter writer) + { + return base.Write(writer); + } + } +} diff --git a/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_LocalOutVariable.cs b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_LocalOutVariable.cs new file mode 100644 index 0000000..416ddc7 --- /dev/null +++ b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_LocalOutVariable.cs @@ -0,0 +1,46 @@ +using Newtonsoft.Json; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.Kismet.Bytecode.Expressions +{ + /// + /// A single Kismet bytecode instruction, corresponding to the instruction. + /// + public class EX_LocalOutVariable : KismetExpression + { + /// + /// The token of this expression. + /// + public override EExprToken Token { get { return EExprToken.EX_LocalOutVariable; } } + + /// + /// A pointer to the variable in question. + /// + [JsonProperty] + public KismetPropertyPointer Variable; + + public EX_LocalOutVariable() + { + + } + + /// + /// Reads out the expression from a BinaryReader. + /// + /// The BinaryReader to read from. + public override void Read(AssetBinaryReader reader) + { + Variable = reader.XFER_PROP_POINTER(); + } + + /// + /// Writes the expression to a BinaryWriter. + /// + /// The BinaryWriter to write from. + /// The iCode offset of the data that was written. + public override int Write(AssetBinaryWriter writer) + { + return writer.XFER_PROP_POINTER(Variable); + } + } +} diff --git a/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_LocalVariable.cs b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_LocalVariable.cs new file mode 100644 index 0000000..c6fb720 --- /dev/null +++ b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_LocalVariable.cs @@ -0,0 +1,46 @@ +using Newtonsoft.Json; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.Kismet.Bytecode.Expressions +{ + /// + /// A single Kismet bytecode instruction, corresponding to the instruction. + /// + public class EX_LocalVariable : KismetExpression + { + /// + /// The token of this expression. + /// + public override EExprToken Token { get { return EExprToken.EX_LocalVariable; } } + + /// + /// A pointer to the variable in question. + /// + [JsonProperty] + public KismetPropertyPointer Variable; + + public EX_LocalVariable() + { + + } + + /// + /// Reads out the expression from a BinaryReader. + /// + /// The BinaryReader to read from. + public override void Read(AssetBinaryReader reader) + { + Variable = reader.XFER_PROP_POINTER(); + } + + /// + /// Writes the expression to a BinaryWriter. + /// + /// The BinaryWriter to write from. + /// The iCode offset of the data that was written. + public override int Write(AssetBinaryWriter writer) + { + return writer.XFER_PROP_POINTER(Variable); + } + } +} diff --git a/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_LocalVirtualFunction.cs b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_LocalVirtualFunction.cs new file mode 100644 index 0000000..b6cf26a --- /dev/null +++ b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_LocalVirtualFunction.cs @@ -0,0 +1,37 @@ +namespace UAssetAPI.Kismet.Bytecode.Expressions +{ + /// + /// A single Kismet bytecode instruction, corresponding to the instruction. + /// + public class EX_LocalVirtualFunction : EX_VirtualFunction + { + /// + /// The token of this expression. + /// + public override EExprToken Token { get { return EExprToken.EX_LocalVirtualFunction; } } + + public EX_LocalVirtualFunction() : base() + { + + } + + /// + /// Reads out the expression from a BinaryReader. + /// + /// The BinaryReader to read from. + public override void Read(AssetBinaryReader reader) + { + base.Read(reader); + } + + /// + /// Writes the expression to a BinaryWriter. + /// + /// The BinaryWriter to write from. + /// The iCode offset of the data that was written. + public override int Write(AssetBinaryWriter writer) + { + return base.Write(writer); + } + } +} diff --git a/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_MapConst.cs b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_MapConst.cs new file mode 100644 index 0000000..d415805 --- /dev/null +++ b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_MapConst.cs @@ -0,0 +1,70 @@ +using Newtonsoft.Json; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.Kismet.Bytecode.Expressions +{ + /// + /// A single Kismet bytecode instruction, corresponding to the instruction. + /// + public class EX_MapConst : KismetExpression + { + /// + /// The token of this expression. + /// + public override EExprToken Token { get { return EExprToken.EX_MapConst; } } + + /// + /// Pointer to this constant's key property (FProperty*). + /// + [JsonProperty] + public KismetPropertyPointer KeyProperty; + + /// + /// Pointer to this constant's value property (FProperty*). + /// + [JsonProperty] + public KismetPropertyPointer ValueProperty; + + /// + /// Set constant entries. + /// + [JsonProperty] + public KismetExpression[] Elements; + + public EX_MapConst() + { + + } + + /// + /// Reads out the expression from a BinaryReader. + /// + /// The BinaryReader to read from. + public override void Read(AssetBinaryReader reader) + { + KeyProperty = reader.XFER_PROP_POINTER(); + ValueProperty = reader.XFER_PROP_POINTER(); + int numEntries = reader.ReadInt32(); // Number of elements + Elements = reader.ReadExpressionArray(EExprToken.EX_EndMapConst); + } + + /// + /// Writes the expression to a BinaryWriter. + /// + /// The BinaryWriter to write from. + /// The iCode offset of the data that was written. + public override int Write(AssetBinaryWriter writer) + { + int offset = 0; + offset += writer.XFER_PROP_POINTER(KeyProperty); + offset += writer.XFER_PROP_POINTER(ValueProperty); + writer.Write(Elements.Length); offset += sizeof(int); + for (int i = 0; i < Elements.Length; i++) + { + offset += ExpressionSerializer.WriteExpression(Elements[i], writer); + } + offset += ExpressionSerializer.WriteExpression(new EX_EndMapConst(), writer); + return offset; + } + } +} diff --git a/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_MetaCast.cs b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_MetaCast.cs new file mode 100644 index 0000000..05cde3b --- /dev/null +++ b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_MetaCast.cs @@ -0,0 +1,56 @@ +using Newtonsoft.Json; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.Kismet.Bytecode.Expressions +{ + /// + /// A single Kismet bytecode instruction, corresponding to the instruction. + /// + public class EX_MetaCast : KismetExpression + { + /// + /// The token of this expression. + /// + public override EExprToken Token { get { return EExprToken.EX_MetaCast; } } + + /// + /// A pointer to the relevant class (UClass*). + /// + [JsonProperty] + public FPackageIndex ClassPtr; + + /// + /// The target expression. + /// + [JsonProperty] + public KismetExpression TargetExpression; + + public EX_MetaCast() + { + + } + + /// + /// Reads out the expression from a BinaryReader. + /// + /// The BinaryReader to read from. + public override void Read(AssetBinaryReader reader) + { + ClassPtr = reader.XFER_OBJECT_POINTER(); + TargetExpression = ExpressionSerializer.ReadExpression(reader); + } + + /// + /// Writes the expression to a BinaryWriter. + /// + /// The BinaryWriter to write from. + /// The iCode offset of the data that was written. + public override int Write(AssetBinaryWriter writer) + { + int offset = 0; + offset += writer.XFER_OBJECT_POINTER(ClassPtr); + offset += ExpressionSerializer.WriteExpression(TargetExpression, writer); + return offset; + } + } +} diff --git a/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_NameConst.cs b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_NameConst.cs new file mode 100644 index 0000000..2c46ca5 --- /dev/null +++ b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_NameConst.cs @@ -0,0 +1,39 @@ +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.Kismet.Bytecode.Expressions +{ + /// + /// A single Kismet bytecode instruction, corresponding to the instruction. + /// + public class EX_NameConst : KismetExpression + { + /// + /// The token of this expression. + /// + public override EExprToken Token { get { return EExprToken.EX_NameConst; } } + + public EX_NameConst() + { + + } + + /// + /// Reads out the expression from a BinaryReader. + /// + /// The BinaryReader to read from. + public override void Read(AssetBinaryReader reader) + { + Value = reader.XFERNAME(); + } + + /// + /// Writes the expression to a BinaryWriter. + /// + /// The BinaryWriter to write from. + /// The iCode offset of the data that was written. + public override int Write(AssetBinaryWriter writer) + { + return writer.XFERNAME(Value); + } + } +} diff --git a/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_NoInterface.cs b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_NoInterface.cs new file mode 100644 index 0000000..1414759 --- /dev/null +++ b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_NoInterface.cs @@ -0,0 +1,37 @@ +namespace UAssetAPI.Kismet.Bytecode.Expressions +{ + /// + /// A single Kismet bytecode instruction, corresponding to the instruction. + /// + public class EX_NoInterface : KismetExpression + { + /// + /// The token of this expression. + /// + public override EExprToken Token { get { return EExprToken.EX_NoInterface; } } + + public EX_NoInterface() + { + + } + + /// + /// Reads out the expression from a BinaryReader. + /// + /// The BinaryReader to read from. + public override void Read(AssetBinaryReader reader) + { + + } + + /// + /// Writes the expression to a BinaryWriter. + /// + /// The BinaryWriter to write from. + /// The iCode offset of the data that was written. + public override int Write(AssetBinaryWriter writer) + { + return 0; + } + } +} diff --git a/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_NoObject.cs b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_NoObject.cs new file mode 100644 index 0000000..10c7a90 --- /dev/null +++ b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_NoObject.cs @@ -0,0 +1,37 @@ +namespace UAssetAPI.Kismet.Bytecode.Expressions +{ + /// + /// A single Kismet bytecode instruction, corresponding to the instruction. + /// + public class EX_NoObject : KismetExpression + { + /// + /// The token of this expression. + /// + public override EExprToken Token { get { return EExprToken.EX_NoObject; } } + + public EX_NoObject() + { + + } + + /// + /// Reads out the expression from a BinaryReader. + /// + /// The BinaryReader to read from. + public override void Read(AssetBinaryReader reader) + { + + } + + /// + /// Writes the expression to a BinaryWriter. + /// + /// The BinaryWriter to write from. + /// The iCode offset of the data that was written. + public override int Write(AssetBinaryWriter writer) + { + return 0; + } + } +} diff --git a/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_Nothing.cs b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_Nothing.cs new file mode 100644 index 0000000..c3e0d3d --- /dev/null +++ b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_Nothing.cs @@ -0,0 +1,38 @@ +namespace UAssetAPI.Kismet.Bytecode.Expressions +{ + /// + /// A single Kismet bytecode instruction, corresponding to the instruction. + /// Represents a no-op. + /// + public class EX_Nothing : KismetExpression + { + /// + /// The token of this expression. + /// + public override EExprToken Token { get { return EExprToken.EX_Nothing; } } + + public EX_Nothing() + { + + } + + /// + /// Reads out the expression from a BinaryReader. + /// + /// The BinaryReader to read from. + public override void Read(AssetBinaryReader reader) + { + + } + + /// + /// Writes the expression to a BinaryWriter. + /// + /// The BinaryWriter to write from. + /// The iCode offset of the data that was written. + public override int Write(AssetBinaryWriter writer) + { + return 0; + } + } +} diff --git a/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_ObjToInterfaceCast.cs b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_ObjToInterfaceCast.cs new file mode 100644 index 0000000..61d7896 --- /dev/null +++ b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_ObjToInterfaceCast.cs @@ -0,0 +1,57 @@ +using Newtonsoft.Json; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.Kismet.Bytecode.Expressions +{ + /// + /// A single Kismet bytecode instruction, corresponding to the instruction. + /// A conversion from an object or interface variable to a native interface variable. + /// + public class EX_ObjToInterfaceCast : KismetExpression + { + /// + /// The token of this expression. + /// + public override EExprToken Token { get { return EExprToken.EX_ObjToInterfaceCast; } } + + /// + /// A pointer to the interface class to convert to. + /// + [JsonProperty] + public FPackageIndex ClassPtr; + + /// + /// The target of this expression. + /// + [JsonProperty] + public KismetExpression Target; + + public EX_ObjToInterfaceCast() + { + + } + + /// + /// Reads out the expression from a BinaryReader. + /// + /// The BinaryReader to read from. + public override void Read(AssetBinaryReader reader) + { + ClassPtr = reader.XFER_OBJECT_POINTER(); + Target = ExpressionSerializer.ReadExpression(reader); + } + + /// + /// Writes the expression to a BinaryWriter. + /// + /// The BinaryWriter to write from. + /// The iCode offset of the data that was written. + public override int Write(AssetBinaryWriter writer) + { + int offset = 0; + offset += writer.XFER_OBJECT_POINTER(ClassPtr); + offset += ExpressionSerializer.WriteExpression(Target, writer); + return offset; + } + } +} diff --git a/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_ObjectConst.cs b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_ObjectConst.cs new file mode 100644 index 0000000..2f798de --- /dev/null +++ b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_ObjectConst.cs @@ -0,0 +1,39 @@ +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.Kismet.Bytecode.Expressions +{ + /// + /// A single Kismet bytecode instruction, corresponding to the instruction. + /// + public class EX_ObjectConst : KismetExpression + { + /// + /// The token of this expression. + /// + public override EExprToken Token { get { return EExprToken.EX_ObjectConst; } } + + public EX_ObjectConst() + { + + } + + /// + /// Reads out the expression from a BinaryReader. + /// + /// The BinaryReader to read from. + public override void Read(AssetBinaryReader reader) + { + Value = reader.XFER_OBJECT_POINTER(); + } + + /// + /// Writes the expression to a BinaryWriter. + /// + /// The BinaryWriter to write from. + /// The iCode offset of the data that was written. + public override int Write(AssetBinaryWriter writer) + { + return writer.XFER_OBJECT_POINTER(Value); + } + } +} diff --git a/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_PopExecutionFlow.cs b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_PopExecutionFlow.cs new file mode 100644 index 0000000..a2b2139 --- /dev/null +++ b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_PopExecutionFlow.cs @@ -0,0 +1,37 @@ +namespace UAssetAPI.Kismet.Bytecode.Expressions +{ + /// + /// A single Kismet bytecode instruction, corresponding to the instruction. + /// + public class EX_PopExecutionFlow : KismetExpression + { + /// + /// The token of this expression. + /// + public override EExprToken Token { get { return EExprToken.EX_PopExecutionFlow; } } + + public EX_PopExecutionFlow() + { + + } + + /// + /// Reads out the expression from a BinaryReader. + /// + /// The BinaryReader to read from. + public override void Read(AssetBinaryReader reader) + { + + } + + /// + /// Writes the expression to a BinaryWriter. + /// + /// The BinaryWriter to write from. + /// The iCode offset of the data that was written. + public override int Write(AssetBinaryWriter writer) + { + return 0; + } + } +} diff --git a/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_PopExecutionFlowIfNot.cs b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_PopExecutionFlowIfNot.cs new file mode 100644 index 0000000..2650f33 --- /dev/null +++ b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_PopExecutionFlowIfNot.cs @@ -0,0 +1,47 @@ +using Newtonsoft.Json; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.Kismet.Bytecode.Expressions +{ + /// + /// A single Kismet bytecode instruction, corresponding to the instruction. + /// Conditional equivalent of the expression. + /// + public class EX_PopExecutionFlowIfNot : KismetExpression + { + /// + /// The token of this expression. + /// + public override EExprToken Token { get { return EExprToken.EX_PopExecutionFlowIfNot; } } + + /// + /// Expression to evaluate to determine whether or not a pop should be performed. + /// + [JsonProperty] + public KismetExpression BooleanExpression; + + public EX_PopExecutionFlowIfNot() + { + + } + + /// + /// Reads out the expression from a BinaryReader. + /// + /// The BinaryReader to read from. + public override void Read(AssetBinaryReader reader) + { + BooleanExpression = ExpressionSerializer.ReadExpression(reader); + } + + /// + /// Writes the expression to a BinaryWriter. + /// + /// The BinaryWriter to write from. + /// The iCode offset of the data that was written. + public override int Write(AssetBinaryWriter writer) + { + return ExpressionSerializer.WriteExpression(BooleanExpression, writer); + } + } +} diff --git a/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_PrimitiveCast.cs b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_PrimitiveCast.cs new file mode 100644 index 0000000..55dacfa --- /dev/null +++ b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_PrimitiveCast.cs @@ -0,0 +1,56 @@ +using Newtonsoft.Json; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.Kismet.Bytecode.Expressions +{ + /// + /// A single Kismet bytecode instruction, corresponding to the instruction. + /// + public class EX_PrimitiveCast : KismetExpression + { + /// + /// The type to cast to. + /// + [JsonProperty] + public ECastToken ConversionType; + + /// + /// The target of this expression. + /// + [JsonProperty] + public KismetExpression Target; + + /// + /// The token of this expression. + /// + public override EExprToken Token { get { return EExprToken.EX_PrimitiveCast; } } + + public EX_PrimitiveCast() + { + + } + + /// + /// Reads out the expression from a BinaryReader. + /// + /// The BinaryReader to read from. + public override void Read(AssetBinaryReader reader) + { + ConversionType = (ECastToken)reader.ReadByte(); + Target = ExpressionSerializer.ReadExpression(reader); + } + + /// + /// Writes the expression to a BinaryWriter. + /// + /// The BinaryWriter to write from. + /// The iCode offset of the data that was written. + public override int Write(AssetBinaryWriter writer) + { + int offset = 0; + writer.Write((byte)ConversionType); offset += sizeof(byte); + offset += ExpressionSerializer.WriteExpression(Target, writer); + return offset; + } + } +} diff --git a/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_PropertyConst.cs b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_PropertyConst.cs new file mode 100644 index 0000000..9107ccd --- /dev/null +++ b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_PropertyConst.cs @@ -0,0 +1,46 @@ +using Newtonsoft.Json; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.Kismet.Bytecode.Expressions +{ + /// + /// A single Kismet bytecode instruction, corresponding to the instruction. + /// + public class EX_PropertyConst : KismetExpression + { + /// + /// The token of this expression. + /// + public override EExprToken Token { get { return EExprToken.EX_PropertyConst; } } + + /// + /// A pointer to the property in question. + /// + [JsonProperty] + public KismetPropertyPointer Property; + + public EX_PropertyConst() + { + + } + + /// + /// Reads out the expression from a BinaryReader. + /// + /// The BinaryReader to read from. + public override void Read(AssetBinaryReader reader) + { + Property = reader.XFER_PROP_POINTER(); + } + + /// + /// Writes the expression to a BinaryWriter. + /// + /// The BinaryWriter to write from. + /// The iCode offset of the data that was written. + public override int Write(AssetBinaryWriter writer) + { + return writer.XFER_PROP_POINTER(Property); + } + } +} diff --git a/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_PushExecutionFlow.cs b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_PushExecutionFlow.cs new file mode 100644 index 0000000..3a5cd7c --- /dev/null +++ b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_PushExecutionFlow.cs @@ -0,0 +1,47 @@ +using Newtonsoft.Json; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.Kismet.Bytecode.Expressions +{ + /// + /// A single Kismet bytecode instruction, corresponding to the instruction. + /// + public class EX_PushExecutionFlow : KismetExpression + { + /// + /// The token of this expression. + /// + public override EExprToken Token { get { return EExprToken.EX_PushExecutionFlow; } } + + /// + /// The address to push onto the execution flow stack. + /// + [JsonProperty] + public uint PushingAddress; + + public EX_PushExecutionFlow() + { + + } + + /// + /// Reads out the expression from a BinaryReader. + /// + /// The BinaryReader to read from. + public override void Read(AssetBinaryReader reader) + { + PushingAddress = reader.ReadUInt32(); + } + + /// + /// Writes the expression to a BinaryWriter. + /// + /// The BinaryWriter to write from. + /// The iCode offset of the data that was written. + public override int Write(AssetBinaryWriter writer) + { + writer.Write(PushingAddress); + return sizeof(uint); + } + } +} diff --git a/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_RemoveMulticastDelegate.cs b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_RemoveMulticastDelegate.cs new file mode 100644 index 0000000..8c703ec --- /dev/null +++ b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_RemoveMulticastDelegate.cs @@ -0,0 +1,56 @@ +using Newtonsoft.Json; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.Kismet.Bytecode.Expressions +{ + /// + /// A single Kismet bytecode instruction, corresponding to the instruction. + /// + public class EX_RemoveMulticastDelegate : KismetExpression + { + /// + /// The token of this expression. + /// + public override EExprToken Token { get { return EExprToken.EX_RemoveMulticastDelegate; } } + + /// + /// Delegate property to assign to. + /// + [JsonProperty] + public KismetExpression Delegate; + + /// + /// Delegate to add to the MC delegate for broadcast. + /// + [JsonProperty] + public KismetExpression DelegateToAdd; + + public EX_RemoveMulticastDelegate() + { + + } + + /// + /// Reads out the expression from a BinaryReader. + /// + /// The BinaryReader to read from. + public override void Read(AssetBinaryReader reader) + { + Delegate = ExpressionSerializer.ReadExpression(reader); + DelegateToAdd = ExpressionSerializer.ReadExpression(reader); + } + + /// + /// Writes the expression to a BinaryWriter. + /// + /// The BinaryWriter to write from. + /// The iCode offset of the data that was written. + public override int Write(AssetBinaryWriter writer) + { + int offset = 0; + offset += ExpressionSerializer.WriteExpression(Delegate, writer); + offset += ExpressionSerializer.WriteExpression(DelegateToAdd, writer); + return offset; + } + } +} diff --git a/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_Return.cs b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_Return.cs new file mode 100644 index 0000000..6d2e79f --- /dev/null +++ b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_Return.cs @@ -0,0 +1,46 @@ +using Newtonsoft.Json; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.Kismet.Bytecode.Expressions +{ + /// + /// A single Kismet bytecode instruction, corresponding to the instruction. + /// + public class EX_Return : KismetExpression + { + /// + /// The token of this expression. + /// + public override EExprToken Token { get { return EExprToken.EX_Return; } } + + /// + /// The return expression. + /// + [JsonProperty] + public KismetExpression ReturnExpression; + + public EX_Return() + { + + } + + /// + /// Reads out the expression from a BinaryReader. + /// + /// The BinaryReader to read from. + public override void Read(AssetBinaryReader reader) + { + ReturnExpression = ExpressionSerializer.ReadExpression(reader); + } + + /// + /// Writes the expression to a BinaryWriter. + /// + /// The BinaryWriter to write from. + /// The iCode offset of the data that was written. + public override int Write(AssetBinaryWriter writer) + { + return ExpressionSerializer.WriteExpression(ReturnExpression, writer); + } + } +} diff --git a/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_RotationConst.cs b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_RotationConst.cs new file mode 100644 index 0000000..b3848d5 --- /dev/null +++ b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_RotationConst.cs @@ -0,0 +1,57 @@ +using Newtonsoft.Json; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.Kismet.Bytecode.Expressions +{ + /// + /// A single Kismet bytecode instruction, corresponding to the instruction. + /// + public class EX_RotationConst : KismetExpression + { + /// Rotation around the right axis (around Y axis), Looking up and down (0=Straight Ahead, +Up, -Down) + [JsonProperty] + public int Pitch; + + /// Rotation around the up axis (around Z axis), Running in circles 0=East, +North, -South. + [JsonProperty] + public int Yaw; + + /// Rotation around the forward axis (around X axis), Tilting your head, 0=Straight, +Clockwise, -CCW. + [JsonProperty] + public int Roll; + + /// + /// The token of this expression. + /// + public override EExprToken Token { get { return EExprToken.EX_RotationConst; } } + + public EX_RotationConst() + { + + } + + /// + /// Reads out the expression from a BinaryReader. + /// + /// The BinaryReader to read from. + public override void Read(AssetBinaryReader reader) + { + Pitch = reader.ReadInt32(); + Yaw = reader.ReadInt32(); + Roll = reader.ReadInt32(); + } + + /// + /// Writes the expression to a BinaryWriter. + /// + /// The BinaryWriter to write from. + /// The iCode offset of the data that was written. + public override int Write(AssetBinaryWriter writer) + { + writer.Write(Pitch); + writer.Write(Yaw); + writer.Write(Roll); + return sizeof(int) * 3; + } + } +} diff --git a/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_Self.cs b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_Self.cs new file mode 100644 index 0000000..036e0fa --- /dev/null +++ b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_Self.cs @@ -0,0 +1,37 @@ +namespace UAssetAPI.Kismet.Bytecode.Expressions +{ + /// + /// A single Kismet bytecode instruction, corresponding to the instruction. + /// + public class EX_Self : KismetExpression + { + /// + /// The token of this expression. + /// + public override EExprToken Token { get { return EExprToken.EX_Self; } } + + public EX_Self() + { + + } + + /// + /// Reads out the expression from a BinaryReader. + /// + /// The BinaryReader to read from. + public override void Read(AssetBinaryReader reader) + { + + } + + /// + /// Writes the expression to a BinaryWriter. + /// + /// The BinaryWriter to write from. + /// The iCode offset of the data that was written. + public override int Write(AssetBinaryWriter writer) + { + return 0; + } + } +} diff --git a/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_SetArray.cs b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_SetArray.cs new file mode 100644 index 0000000..cef3f64 --- /dev/null +++ b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_SetArray.cs @@ -0,0 +1,83 @@ +using Newtonsoft.Json; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.Kismet.Bytecode.Expressions +{ + /// + /// A single Kismet bytecode instruction, corresponding to the instruction. + /// + public class EX_SetArray : KismetExpression + { + /// + /// The token of this expression. + /// + public override EExprToken Token { get { return EExprToken.EX_SetArray; } } + + /// + /// Array property to assign to + /// + [JsonProperty] + public KismetExpression AssigningProperty; + + /// + /// Pointer to the array inner property (FProperty*). + /// Only used in engine versions prior to . + /// + [JsonProperty] + public FPackageIndex ArrayInnerProp; + + /// + /// Array items. + /// + [JsonProperty] + public KismetExpression[] Elements; + + public EX_SetArray() + { + + } + + /// + /// Reads out the expression from a BinaryReader. + /// + /// The BinaryReader to read from. + public override void Read(AssetBinaryReader reader) + { + if (reader.Asset.EngineVersion >= UE4Version.VER_UE4_CHANGE_SETARRAY_BYTECODE) + { + AssigningProperty = ExpressionSerializer.ReadExpression(reader); + } + else + { + ArrayInnerProp = reader.XFERPTR(); + } + + Elements = reader.ReadExpressionArray(EExprToken.EX_EndArray); + } + + /// + /// Writes the expression to a BinaryWriter. + /// + /// The BinaryWriter to write from. + /// The iCode offset of the data that was written. + public override int Write(AssetBinaryWriter writer) + { + int offset = 0; + if (writer.Asset.EngineVersion >= UE4Version.VER_UE4_CHANGE_SETARRAY_BYTECODE) + { + offset += ExpressionSerializer.WriteExpression(AssigningProperty, writer); + } + else + { + offset += writer.XFERPTR(ArrayInnerProp); + } + + for (int i = 0; i < Elements.Length; i++) + { + offset += ExpressionSerializer.WriteExpression(Elements[i], writer); + } + offset += ExpressionSerializer.WriteExpression(new EX_EndArray(), writer); + return offset; + } + } +} diff --git a/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_SetConst.cs b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_SetConst.cs new file mode 100644 index 0000000..5af3085 --- /dev/null +++ b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_SetConst.cs @@ -0,0 +1,62 @@ +using Newtonsoft.Json; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.Kismet.Bytecode.Expressions +{ + /// + /// A single Kismet bytecode instruction, corresponding to the instruction. + /// + public class EX_SetConst : KismetExpression + { + /// + /// The token of this expression. + /// + public override EExprToken Token { get { return EExprToken.EX_SetConst; } } + + /// + /// Pointer to this constant's inner property (FProperty*). + /// + [JsonProperty] + public KismetPropertyPointer InnerProperty; + + /// + /// Set constant entries. + /// + [JsonProperty] + public KismetExpression[] Elements; + + public EX_SetConst() + { + + } + + /// + /// Reads out the expression from a BinaryReader. + /// + /// The BinaryReader to read from. + public override void Read(AssetBinaryReader reader) + { + InnerProperty = reader.XFER_PROP_POINTER(); + int numEntries = reader.ReadInt32(); // Number of elements + Elements = reader.ReadExpressionArray(EExprToken.EX_EndSetConst); + } + + /// + /// Writes the expression to a BinaryWriter. + /// + /// The BinaryWriter to write from. + /// The iCode offset of the data that was written. + public override int Write(AssetBinaryWriter writer) + { + int offset = 0; + offset += writer.XFER_PROP_POINTER(InnerProperty); + writer.Write(Elements.Length); offset += sizeof(int); + for (int i = 0; i < Elements.Length; i++) + { + offset += ExpressionSerializer.WriteExpression(Elements[i], writer); + } + offset += ExpressionSerializer.WriteExpression(new EX_EndSetConst(), writer); + return offset; + } + } +} diff --git a/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_SetMap.cs b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_SetMap.cs new file mode 100644 index 0000000..b209e30 --- /dev/null +++ b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_SetMap.cs @@ -0,0 +1,62 @@ +using Newtonsoft.Json; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.Kismet.Bytecode.Expressions +{ + /// + /// A single Kismet bytecode instruction, corresponding to the instruction. + /// + public class EX_SetMap : KismetExpression + { + /// + /// The token of this expression. + /// + public override EExprToken Token { get { return EExprToken.EX_SetMap; } } + + /// + /// Map property. + /// + [JsonProperty] + public KismetExpression MapProperty; + + /// + /// Set entries. + /// + [JsonProperty] + public KismetExpression[] Elements; + + public EX_SetMap() + { + + } + + /// + /// Reads out the expression from a BinaryReader. + /// + /// The BinaryReader to read from. + public override void Read(AssetBinaryReader reader) + { + MapProperty = ExpressionSerializer.ReadExpression(reader); + int numEntries = reader.ReadInt32(); // Number of elements + Elements = reader.ReadExpressionArray(EExprToken.EX_EndMap); + } + + /// + /// Writes the expression to a BinaryWriter. + /// + /// The BinaryWriter to write from. + /// The iCode offset of the data that was written. + public override int Write(AssetBinaryWriter writer) + { + int offset = 0; + offset += ExpressionSerializer.WriteExpression(MapProperty, writer); + writer.Write(Elements.Length); offset += sizeof(int); + for (int i = 0; i < Elements.Length; i++) + { + offset += ExpressionSerializer.WriteExpression(Elements[i], writer); + } + offset += ExpressionSerializer.WriteExpression(new EX_EndMap(), writer); + return offset; + } + } +} diff --git a/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_SetSet.cs b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_SetSet.cs new file mode 100644 index 0000000..367fb3f --- /dev/null +++ b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_SetSet.cs @@ -0,0 +1,62 @@ +using Newtonsoft.Json; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.Kismet.Bytecode.Expressions +{ + /// + /// A single Kismet bytecode instruction, corresponding to the instruction. + /// + public class EX_SetSet : KismetExpression + { + /// + /// The token of this expression. + /// + public override EExprToken Token { get { return EExprToken.EX_SetSet; } } + + /// + /// Set property. + /// + [JsonProperty] + public KismetExpression SetProperty; + + /// + /// Set entries. + /// + [JsonProperty] + public KismetExpression[] Elements; + + public EX_SetSet() + { + + } + + /// + /// Reads out the expression from a BinaryReader. + /// + /// The BinaryReader to read from. + public override void Read(AssetBinaryReader reader) + { + SetProperty = ExpressionSerializer.ReadExpression(reader); + int numEntries = reader.ReadInt32(); // Number of elements + Elements = reader.ReadExpressionArray(EExprToken.EX_EndSet); + } + + /// + /// Writes the expression to a BinaryWriter. + /// + /// The BinaryWriter to write from. + /// The iCode offset of the data that was written. + public override int Write(AssetBinaryWriter writer) + { + int offset = 0; + offset += ExpressionSerializer.WriteExpression(SetProperty, writer); + writer.Write(Elements.Length); offset += sizeof(int); + for (int i = 0; i < Elements.Length; i++) + { + offset += ExpressionSerializer.WriteExpression(Elements[i], writer); + } + offset += ExpressionSerializer.WriteExpression(new EX_EndSet(), writer); + return offset; + } + } +} diff --git a/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_Skip.cs b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_Skip.cs new file mode 100644 index 0000000..a397a38 --- /dev/null +++ b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_Skip.cs @@ -0,0 +1,56 @@ +using Newtonsoft.Json; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.Kismet.Bytecode.Expressions +{ + /// + /// A single Kismet bytecode instruction, corresponding to the instruction. + /// + public class EX_Skip : KismetExpression + { + /// + /// The token of this expression. + /// + public override EExprToken Token { get { return EExprToken.EX_Skip; } } + + /// + /// The offset to skip to. + /// + [JsonProperty] + public uint CodeOffset; + + /// + /// An expression to possibly skip. + /// + [JsonProperty] + public KismetExpression SkipExpression; + + public EX_Skip() + { + + } + + /// + /// Reads out the expression from a BinaryReader. + /// + /// The BinaryReader to read from. + public override void Read(AssetBinaryReader reader) + { + CodeOffset = reader.ReadUInt32(); + SkipExpression = ExpressionSerializer.ReadExpression(reader); + } + + /// + /// Writes the expression to a BinaryWriter. + /// + /// The BinaryWriter to write from. + /// The iCode offset of the data that was written. + public override int Write(AssetBinaryWriter writer) + { + int offset = 0; + writer.Write(CodeOffset); offset += sizeof(uint); + offset += ExpressionSerializer.WriteExpression(SkipExpression, writer); + return offset; + } + } +} diff --git a/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_SkipOffsetConst.cs b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_SkipOffsetConst.cs new file mode 100644 index 0000000..b9f766e --- /dev/null +++ b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_SkipOffsetConst.cs @@ -0,0 +1,39 @@ +namespace UAssetAPI.Kismet.Bytecode.Expressions +{ + /// + /// A single Kismet bytecode instruction, corresponding to the instruction. + /// Represents a code offset constant. + /// + public class EX_SkipOffsetConst : KismetExpression + { + /// + /// The token of this expression. + /// + public override EExprToken Token { get { return EExprToken.EX_SkipOffsetConst; } } + + public EX_SkipOffsetConst() + { + + } + + /// + /// Reads out the expression from a BinaryReader. + /// + /// The BinaryReader to read from. + public override void Read(AssetBinaryReader reader) + { + Value = reader.ReadUInt32(); + } + + /// + /// Writes the expression to a BinaryWriter. + /// + /// The BinaryWriter to write from. + /// The iCode offset of the data that was written. + public override int Write(AssetBinaryWriter writer) + { + writer.Write(Value); + return sizeof(uint); + } + } +} diff --git a/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_SoftObjectConst.cs b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_SoftObjectConst.cs new file mode 100644 index 0000000..d028e2f --- /dev/null +++ b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_SoftObjectConst.cs @@ -0,0 +1,37 @@ +namespace UAssetAPI.Kismet.Bytecode.Expressions +{ + /// + /// A single Kismet bytecode instruction, corresponding to the instruction. + /// + public class EX_SoftObjectConst : KismetExpression + { + /// + /// The token of this expression. + /// + public override EExprToken Token { get { return EExprToken.EX_SoftObjectConst; } } + + public EX_SoftObjectConst() + { + + } + + /// + /// Reads out the expression from a BinaryReader. + /// + /// The BinaryReader to read from. + public override void Read(AssetBinaryReader reader) + { + Value = ExpressionSerializer.ReadExpression(reader); + } + + /// + /// Writes the expression to a BinaryWriter. + /// + /// The BinaryWriter to write from. + /// The iCode offset of the data that was written. + public override int Write(AssetBinaryWriter writer) + { + return ExpressionSerializer.WriteExpression(Value, writer); + } + } +} diff --git a/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_StringConst.cs b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_StringConst.cs new file mode 100644 index 0000000..1d63918 --- /dev/null +++ b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_StringConst.cs @@ -0,0 +1,37 @@ +namespace UAssetAPI.Kismet.Bytecode.Expressions +{ + /// + /// A single Kismet bytecode instruction, corresponding to the instruction. + /// + public class EX_StringConst : KismetExpression + { + /// + /// The token of this expression. + /// + public override EExprToken Token { get { return EExprToken.EX_StringConst; } } + + public EX_StringConst() + { + + } + + /// + /// Reads out the expression from a BinaryReader. + /// + /// The BinaryReader to read from. + public override void Read(AssetBinaryReader reader) + { + Value = reader.XFERSTRING(); + } + + /// + /// Writes the expression to a BinaryWriter. + /// + /// The BinaryWriter to write from. + /// The iCode offset of the data that was written. + public override int Write(AssetBinaryWriter writer) + { + return writer.XFERSTRING(Value); + } + } +} diff --git a/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_StructConst.cs b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_StructConst.cs new file mode 100644 index 0000000..bf6c7b6 --- /dev/null +++ b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_StructConst.cs @@ -0,0 +1,67 @@ +using Newtonsoft.Json; +using System.Collections.Generic; +using System.IO; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.Kismet.Bytecode.Expressions +{ + /// + /// A single Kismet bytecode instruction, corresponding to the instruction. + /// + public class EX_StructConst : KismetExpression + { + /// + /// The token of this expression. + /// + public override EExprToken Token { get { return EExprToken.EX_StructConst; } } + + /// + /// Pointer to the UScriptStruct in question. + /// + [JsonProperty] + public FPackageIndex Struct; + + /// + /// The size of the struct that this constant represents in memory in bytes. + /// + [JsonProperty] + public int StructSize; + + public EX_StructConst() + { + + } + + /// + /// Reads out the expression from a BinaryReader. + /// + /// The BinaryReader to read from. + public override void Read(AssetBinaryReader reader) + { + Struct = reader.XFERPTR(); + StructSize = reader.ReadInt32(); + Value = reader.ReadExpressionArray(EExprToken.EX_EndStructConst); + } + + /// + /// Writes the expression to a BinaryWriter. + /// + /// The BinaryWriter to write from. + /// The iCode offset of the data that was written. + public override int Write(AssetBinaryWriter writer) + { + int offset = 0; + offset += writer.XFERPTR(Struct); + writer.Write(StructSize); offset += sizeof(int); + + for (int i = 0; i < Value.Length; i++) + { + offset += ExpressionSerializer.WriteExpression(Value[i], writer); + } + + // Write end expression + offset += ExpressionSerializer.WriteExpression(new EX_EndStructConst(), writer); + return offset; + } + } +} diff --git a/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_StructMemberContext.cs b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_StructMemberContext.cs new file mode 100644 index 0000000..2fc8eb7 --- /dev/null +++ b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_StructMemberContext.cs @@ -0,0 +1,56 @@ +using Newtonsoft.Json; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.Kismet.Bytecode.Expressions +{ + /// + /// A single Kismet bytecode instruction, corresponding to the instruction. + /// + public class EX_StructMemberContext : KismetExpression + { + /// + /// The token of this expression. + /// + public override EExprToken Token { get { return EExprToken.EX_StructMemberContext; } } + + /// + /// A pointer to the struct member expression (FProperty*). + /// + [JsonProperty] + public KismetPropertyPointer StructMemberExpression; + + /// + /// Struct expression. + /// + [JsonProperty] + public KismetExpression StructExpression; + + public EX_StructMemberContext() + { + + } + + /// + /// Reads out the expression from a BinaryReader. + /// + /// The BinaryReader to read from. + public override void Read(AssetBinaryReader reader) + { + StructMemberExpression = reader.XFER_PROP_POINTER(); + StructExpression = ExpressionSerializer.ReadExpression(reader); + } + + /// + /// Writes the expression to a BinaryWriter. + /// + /// The BinaryWriter to write from. + /// The iCode offset of the data that was written. + public override int Write(AssetBinaryWriter writer) + { + int offset = 0; + offset += writer.XFER_PROP_POINTER(StructMemberExpression); + offset += ExpressionSerializer.WriteExpression(StructExpression, writer); + return offset; + } + } +} diff --git a/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_SwitchValue.cs b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_SwitchValue.cs new file mode 100644 index 0000000..668ab2e --- /dev/null +++ b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_SwitchValue.cs @@ -0,0 +1,120 @@ +using Newtonsoft.Json; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.Kismet.Bytecode.Expressions +{ + /// + /// Represents a case in a Kismet bytecode switch statement. + /// + [JsonObject(MemberSerialization.OptIn)] + public struct FKismetSwitchCase + { + /// + /// The index value term of this case. + /// + [JsonProperty] + public KismetExpression CaseIndexValueTerm; + + /// + /// Code offset to the next case. + /// + [JsonProperty] + public uint NextOffset; + + /// + /// The main case term. + /// + [JsonProperty] + public KismetExpression CaseTerm; + + public FKismetSwitchCase(KismetExpression caseIndexValueTerm, uint nextOffset, KismetExpression caseTerm) + { + CaseIndexValueTerm = caseIndexValueTerm; + NextOffset = nextOffset; + CaseTerm = caseTerm; + } + } + + /// + /// A single Kismet bytecode instruction, corresponding to the instruction. + /// + public class EX_SwitchValue : KismetExpression + { + /// + /// The token of this expression. + /// + public override EExprToken Token { get { return EExprToken.EX_SwitchValue; } } + + /// + /// Code offset to jump to when finished. + /// + [JsonProperty] + public uint EndGotoOffset; + + /// + /// The index term of this switch statement. + /// + [JsonProperty] + public KismetExpression IndexTerm; + + /// + /// The default term of this switch statement. + /// + [JsonProperty] + public KismetExpression DefaultTerm; + + /// + /// All the cases in this switch statement. + /// + [JsonProperty] + public FKismetSwitchCase[] Cases; + + public EX_SwitchValue() + { + + } + + /// + /// Reads out the expression from a BinaryReader. + /// + /// The BinaryReader to read from. + public override void Read(AssetBinaryReader reader) + { + ushort numCases = reader.ReadUInt16(); // number of cases, without default one + EndGotoOffset = reader.ReadUInt32(); + IndexTerm = ExpressionSerializer.ReadExpression(reader); + + Cases = new FKismetSwitchCase[numCases]; + for (int i = 0; i < numCases; i++) + { + KismetExpression termA = ExpressionSerializer.ReadExpression(reader); + uint termB = reader.ReadUInt32(); + KismetExpression termC = ExpressionSerializer.ReadExpression(reader); + Cases[i] = new FKismetSwitchCase(termA, termB, termC); + } + + DefaultTerm = ExpressionSerializer.ReadExpression(reader); + } + + /// + /// Writes the expression to a BinaryWriter. + /// + /// The BinaryWriter to write from. + /// The iCode offset of the data that was written. + public override int Write(AssetBinaryWriter writer) + { + int offset = 0; + writer.Write((ushort)Cases.Length); offset += sizeof(ushort); + writer.Write(EndGotoOffset); offset += sizeof(uint); + offset += ExpressionSerializer.WriteExpression(IndexTerm, writer); + for (int i = 0; i < Cases.Length; i++) + { + offset += ExpressionSerializer.WriteExpression(Cases[i].CaseIndexValueTerm, writer); + writer.Write(Cases[i].NextOffset); offset += sizeof(uint); + offset += ExpressionSerializer.WriteExpression(Cases[i].CaseTerm, writer); + } + offset += ExpressionSerializer.WriteExpression(DefaultTerm, writer); + return offset; + } + } +} diff --git a/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_TextConst.cs b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_TextConst.cs new file mode 100644 index 0000000..50373da --- /dev/null +++ b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_TextConst.cs @@ -0,0 +1,38 @@ +namespace UAssetAPI.Kismet.Bytecode.Expressions +{ + /// + /// A single Kismet bytecode instruction, corresponding to the instruction. + /// + public class EX_TextConst : KismetExpression + { + /// + /// The token of this expression. + /// + public override EExprToken Token { get { return EExprToken.EX_TextConst; } } + + public EX_TextConst() + { + + } + + /// + /// Reads out the expression from a BinaryReader. + /// + /// The BinaryReader to read from. + public override void Read(AssetBinaryReader reader) + { + Value = new FScriptText(); + Value.Read(reader); + } + + /// + /// Writes the expression to a BinaryWriter. + /// + /// The BinaryWriter to write from. + /// The iCode offset of the data that was written. + public override int Write(AssetBinaryWriter writer) + { + return Value.Write(writer); + } + } +} diff --git a/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_Tracepoint.cs b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_Tracepoint.cs new file mode 100644 index 0000000..366e6f8 --- /dev/null +++ b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_Tracepoint.cs @@ -0,0 +1,37 @@ +namespace UAssetAPI.Kismet.Bytecode.Expressions +{ + /// + /// A single Kismet bytecode instruction, corresponding to the instruction. + /// + public class EX_Tracepoint : KismetExpression + { + /// + /// The token of this expression. + /// + public override EExprToken Token { get { return EExprToken.EX_Tracepoint; } } + + public EX_Tracepoint() + { + + } + + /// + /// Reads out the expression from a BinaryReader. + /// + /// The BinaryReader to read from. + public override void Read(AssetBinaryReader reader) + { + + } + + /// + /// Writes the expression to a BinaryWriter. + /// + /// The BinaryWriter to write from. + /// The iCode offset of the data that was written. + public override int Write(AssetBinaryWriter writer) + { + return 0; + } + } +} diff --git a/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_TransformConst.cs b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_TransformConst.cs new file mode 100644 index 0000000..1c5fc7e --- /dev/null +++ b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_TransformConst.cs @@ -0,0 +1,52 @@ +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.Kismet.Bytecode.Expressions +{ + /// + /// A single Kismet bytecode instruction, corresponding to the instruction. + /// + public class EX_TransformConst : KismetExpression + { + /// + /// The token of this expression. + /// + public override EExprToken Token { get { return EExprToken.EX_TransformConst; } } + + public EX_TransformConst() + { + + } + + /// + /// Reads out the expression from a BinaryReader. + /// + /// The BinaryReader to read from. + public override void Read(AssetBinaryReader reader) + { + var rotation = new FQuat(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle()); + var translation = new FVector(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle()); + var scale = new FVector(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle()); + Value = new FTransform(rotation, translation, scale); + } + + /// + /// Writes the expression to a BinaryWriter. + /// + /// The BinaryWriter to write from. + /// The iCode offset of the data that was written. + public override int Write(AssetBinaryWriter writer) + { + writer.Write(Value.Rotation.X); + writer.Write(Value.Rotation.Y); + writer.Write(Value.Rotation.Z); + writer.Write(Value.Rotation.W); + writer.Write(Value.Translation.X); + writer.Write(Value.Translation.Y); + writer.Write(Value.Translation.Z); + writer.Write(Value.Scale3D.X); + writer.Write(Value.Scale3D.Y); + writer.Write(Value.Scale3D.Z); + return sizeof(float) * 10; + } + } +} diff --git a/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_True.cs b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_True.cs new file mode 100644 index 0000000..1e9d9c7 --- /dev/null +++ b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_True.cs @@ -0,0 +1,37 @@ +namespace UAssetAPI.Kismet.Bytecode.Expressions +{ + /// + /// A single Kismet bytecode instruction, corresponding to the instruction. + /// + public class EX_True : KismetExpression + { + /// + /// The token of this expression. + /// + public override EExprToken Token { get { return EExprToken.EX_True; } } + + public EX_True() + { + + } + + /// + /// Reads out the expression from a BinaryReader. + /// + /// The BinaryReader to read from. + public override void Read(AssetBinaryReader reader) + { + + } + + /// + /// Writes the expression to a BinaryWriter. + /// + /// The BinaryWriter to write from. + /// The iCode offset of the data that was written. + public override int Write(AssetBinaryWriter writer) + { + return 0; + } + } +} diff --git a/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_UInt64Const.cs b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_UInt64Const.cs new file mode 100644 index 0000000..ec78d0b --- /dev/null +++ b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_UInt64Const.cs @@ -0,0 +1,38 @@ +namespace UAssetAPI.Kismet.Bytecode.Expressions +{ + /// + /// A single Kismet bytecode instruction, corresponding to the instruction. + /// + public class EX_UInt64Const : KismetExpression + { + /// + /// The token of this expression. + /// + public override EExprToken Token { get { return EExprToken.EX_UInt64Const; } } + + public EX_UInt64Const() + { + + } + + /// + /// Reads out the expression from a BinaryReader. + /// + /// The BinaryReader to read from. + public override void Read(AssetBinaryReader reader) + { + Value = reader.ReadUInt64(); + } + + /// + /// Writes the expression to a BinaryWriter. + /// + /// The BinaryWriter to write from. + /// The iCode offset of the data that was written. + public override int Write(AssetBinaryWriter writer) + { + writer.Write(Value); + return sizeof(ulong); + } + } +} diff --git a/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_UnicodeStringConst.cs b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_UnicodeStringConst.cs new file mode 100644 index 0000000..80e55d4 --- /dev/null +++ b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_UnicodeStringConst.cs @@ -0,0 +1,37 @@ +namespace UAssetAPI.Kismet.Bytecode.Expressions +{ + /// + /// A single Kismet bytecode instruction, corresponding to the instruction. + /// + public class EX_UnicodeStringConst : KismetExpression + { + /// + /// The token of this expression. + /// + public override EExprToken Token { get { return EExprToken.EX_UnicodeStringConst; } } + + public EX_UnicodeStringConst() + { + + } + + /// + /// Reads out the expression from a BinaryReader. + /// + /// The BinaryReader to read from. + public override void Read(AssetBinaryReader reader) + { + Value = reader.XFERUNICODESTRING(); + } + + /// + /// Writes the expression to a BinaryWriter. + /// + /// The BinaryWriter to write from. + /// The iCode offset of the data that was written. + public override int Write(AssetBinaryWriter writer) + { + return writer.XFERUNICODESTRING(Value); + } + } +} diff --git a/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_VectorConst.cs b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_VectorConst.cs new file mode 100644 index 0000000..7b22176 --- /dev/null +++ b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_VectorConst.cs @@ -0,0 +1,43 @@ +using Newtonsoft.Json; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.Kismet.Bytecode.Expressions +{ + /// + /// A single Kismet bytecode instruction, corresponding to the instruction. + /// + public class EX_VectorConst : KismetExpression + { + /// + /// The token of this expression. + /// + public override EExprToken Token { get { return EExprToken.EX_VectorConst; } } + + public EX_VectorConst() + { + + } + + /// + /// Reads out the expression from a BinaryReader. + /// + /// The BinaryReader to read from. + public override void Read(AssetBinaryReader reader) + { + Value = new FVector(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle()); + } + + /// + /// Writes the expression to a BinaryWriter. + /// + /// The BinaryWriter to write from. + /// The iCode offset of the data that was written. + public override int Write(AssetBinaryWriter writer) + { + writer.Write(Value.X); + writer.Write(Value.Y); + writer.Write(Value.Z); + return sizeof(float) * 3; + } + } +} diff --git a/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_VirtualFunction.cs b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_VirtualFunction.cs new file mode 100644 index 0000000..69eba41 --- /dev/null +++ b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_VirtualFunction.cs @@ -0,0 +1,63 @@ +using Newtonsoft.Json; +using System.Collections.Generic; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.Kismet.Bytecode.Expressions +{ + /// + /// A single Kismet bytecode instruction, corresponding to the instruction. + /// + public class EX_VirtualFunction : KismetExpression + { + /// + /// The token of this expression. + /// + public override EExprToken Token { get { return EExprToken.EX_VirtualFunction; } } + + /// + /// Virtual function name. + /// + [JsonProperty] + public FName VirtualFunctionName; + + /// + /// List of parameters for this function. + /// + [JsonProperty] + public KismetExpression[] Parameters; + + public EX_VirtualFunction() + { + + } + + /// + /// Reads out the expression from a BinaryReader. + /// + /// The BinaryReader to read from. + public override void Read(AssetBinaryReader reader) + { + VirtualFunctionName = reader.XFER_FUNC_NAME(); + + Parameters = reader.ReadExpressionArray(EExprToken.EX_EndFunctionParms); + } + + /// + /// Writes the expression to a BinaryWriter. + /// + /// The BinaryWriter to write from. + /// The iCode offset of the data that was written. + public override int Write(AssetBinaryWriter writer) + { + int offset = 0; + offset += writer.XFER_FUNC_NAME(VirtualFunctionName); + + for (int i = 0; i < Parameters.Length; i++) + { + offset += ExpressionSerializer.WriteExpression(Parameters[i], writer); + } + offset += ExpressionSerializer.WriteExpression(new EX_EndFunctionParms(), writer); + return offset; + } + } +} diff --git a/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_WireTracepoint.cs b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_WireTracepoint.cs new file mode 100644 index 0000000..5644337 --- /dev/null +++ b/Translation/UAssetAPI/Kismet/Bytecode/Expressions/EX_WireTracepoint.cs @@ -0,0 +1,37 @@ +namespace UAssetAPI.Kismet.Bytecode.Expressions +{ + /// + /// A single Kismet bytecode instruction, corresponding to the instruction. + /// + public class EX_WireTracepoint : KismetExpression + { + /// + /// The token of this expression. + /// + public override EExprToken Token { get { return EExprToken.EX_WireTracepoint; } } + + public EX_WireTracepoint() + { + + } + + /// + /// Reads out the expression from a BinaryReader. + /// + /// The BinaryReader to read from. + public override void Read(AssetBinaryReader reader) + { + + } + + /// + /// Writes the expression to a BinaryWriter. + /// + /// The BinaryWriter to write from. + /// The iCode offset of the data that was written. + public override int Write(AssetBinaryWriter writer) + { + return 0; + } + } +} diff --git a/Translation/UAssetAPI/Kismet/Bytecode/FScriptText.cs b/Translation/UAssetAPI/Kismet/Bytecode/FScriptText.cs new file mode 100644 index 0000000..9de5c66 --- /dev/null +++ b/Translation/UAssetAPI/Kismet/Bytecode/FScriptText.cs @@ -0,0 +1,132 @@ +using Newtonsoft.Json; +using System; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.Kismet.Bytecode +{ + /// + /// Represents an FText as serialized in Kismet bytecode. + /// + [JsonObject(MemberSerialization.OptIn)] + public class FScriptText + { + [JsonProperty] + public EBlueprintTextLiteralType TextLiteralType; + + /// + /// Source of this text if it is localized text. Used when is . + /// + [JsonProperty] + public KismetExpression LocalizedSource; + + /// + /// Key of this text if it is localized text. Used when is . + /// + [JsonProperty] + public KismetExpression LocalizedKey; + + /// + /// Namespace of this text if it is localized text. Used when is . + /// + [JsonProperty] + public KismetExpression LocalizedNamespace; + + /// + /// Value of this text if it is an invariant string literal. Used when is . + /// + [JsonProperty] + public KismetExpression InvariantLiteralString; + + /// + /// Value of this text if it is a string literal. Used when is . + /// + [JsonProperty] + public KismetExpression LiteralString; + + /// + /// Pointer to this text's UStringTable. Not used at runtime, but exists for asset dependency gathering. Used when is . + /// + [JsonProperty] + public FPackageIndex StringTableAsset; + + /// + /// Table ID string literal (namespace). Used when is . + /// + [JsonProperty] + public KismetExpression StringTableId; + + /// + /// String table key string literal. Used when is . + /// + [JsonProperty] + public KismetExpression StringTableKey; + + /// + /// Reads out an FBlueprintText from a BinaryReader. + /// + /// The BinaryReader to read from. + public virtual void Read(AssetBinaryReader reader) + { + TextLiteralType = (EBlueprintTextLiteralType)reader.ReadByte(); + switch (TextLiteralType) + { + case EBlueprintTextLiteralType.Empty: + break; + case EBlueprintTextLiteralType.LocalizedText: + LocalizedSource = ExpressionSerializer.ReadExpression(reader); + LocalizedKey = ExpressionSerializer.ReadExpression(reader); + LocalizedNamespace = ExpressionSerializer.ReadExpression(reader); + break; + case EBlueprintTextLiteralType.InvariantText: // IsCultureInvariant + InvariantLiteralString = ExpressionSerializer.ReadExpression(reader); + break; + case EBlueprintTextLiteralType.LiteralString: + LiteralString = ExpressionSerializer.ReadExpression(reader); + break; + case EBlueprintTextLiteralType.StringTableEntry: + StringTableAsset = reader.XFER_OBJECT_POINTER(); + StringTableId = ExpressionSerializer.ReadExpression(reader); + StringTableKey = ExpressionSerializer.ReadExpression(reader); + break; + default: + throw new NotImplementedException("Unimplemented blueprint text literal type " + TextLiteralType); + } + + } + + /// + /// Writes an FBlueprintText to a BinaryWriter. + /// + /// The BinaryWriter to write from. + /// The iCode offset of the data that was written. + public virtual int Write(AssetBinaryWriter writer) + { + int offset = 0; + writer.Write((byte)TextLiteralType); offset += sizeof(byte); + switch (TextLiteralType) + { + case EBlueprintTextLiteralType.Empty: + break; + case EBlueprintTextLiteralType.LocalizedText: + offset += ExpressionSerializer.WriteExpression(LocalizedSource, writer); + offset += ExpressionSerializer.WriteExpression(LocalizedKey, writer); + offset += ExpressionSerializer.WriteExpression(LocalizedNamespace, writer); + break; + case EBlueprintTextLiteralType.InvariantText: // IsCultureInvariant + offset += ExpressionSerializer.WriteExpression(InvariantLiteralString, writer); + break; + case EBlueprintTextLiteralType.LiteralString: + offset += ExpressionSerializer.WriteExpression(LiteralString, writer); + break; + case EBlueprintTextLiteralType.StringTableEntry: + offset += writer.XFER_OBJECT_POINTER(StringTableAsset); + offset += ExpressionSerializer.WriteExpression(StringTableId, writer); + offset += ExpressionSerializer.WriteExpression(StringTableKey, writer); + break; + default: + throw new NotImplementedException("Unimplemented blueprint text literal type " + TextLiteralType); + } + return offset; + } + } +} diff --git a/Translation/UAssetAPI/Kismet/Bytecode/KismetExpression.cs b/Translation/UAssetAPI/Kismet/Bytecode/KismetExpression.cs new file mode 100644 index 0000000..2a028fb --- /dev/null +++ b/Translation/UAssetAPI/Kismet/Bytecode/KismetExpression.cs @@ -0,0 +1,81 @@ +using Newtonsoft.Json; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.Kismet.Bytecode +{ + /// + /// A Kismet bytecode instruction. + /// + [JsonObject(MemberSerialization.OptIn)] + public class KismetExpression + { + /// + /// The token of this expression. + /// + public virtual EExprToken Token { get { return EExprToken.EX_Nothing; } } + + /// + /// The token of this instruction expressed as a string. + /// + public string Inst { get { return Token.ToString().Substring(3, Token.ToString().Length - 3); } } + + /// + /// An optional tag which can be set on any expression in memory. This is for the user only, and has no bearing in the API itself. + /// + public object Tag; + + public object RawValue; + + public void SetObject(object value) + { + RawValue = value; + } + + public T GetObject() + { + return (T)RawValue; + } + + public KismetExpression() + { + + } + + /// + /// Reads out an expression from a BinaryReader. + /// + /// The BinaryReader to read from. + public virtual void Read(AssetBinaryReader reader) + { + + } + + /// + /// Writes an expression to a BinaryWriter. + /// + /// The BinaryWriter to write from. + /// The iCode offset of the data that was written. + public virtual int Write(AssetBinaryWriter writer) + { + return 0; + } + } + + public abstract class KismetExpression : KismetExpression + { + /// + /// The value of this expression if it is a constant. + /// + [JsonProperty] + public T Value + { + get => GetObject(); + set => SetObject(value); + } + + public KismetExpression() : base() + { + + } + } +} diff --git a/Translation/UAssetAPI/Kismet/Bytecode/KismetPropertyPointer.cs b/Translation/UAssetAPI/Kismet/Bytecode/KismetPropertyPointer.cs new file mode 100644 index 0000000..a3ed96b --- /dev/null +++ b/Translation/UAssetAPI/Kismet/Bytecode/KismetPropertyPointer.cs @@ -0,0 +1,54 @@ +using Newtonsoft.Json; +using System.ComponentModel; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.Kismet.Bytecode +{ + /// + /// Represents a Kismet bytecode pointer to an FProperty or FField. + /// + [JsonObject(MemberSerialization.OptIn)] + public class KismetPropertyPointer + { + public static readonly UE4Version XFER_PROP_POINTER_SWITCH_TO_SERIALIZING_AS_FIELD_PATH_VERSION = UE4Version.VER_UE4_ADDED_PACKAGE_OWNER; + + /// + /// The pointer serialized as an FPackageIndex. Used in versions older than . + /// + [JsonProperty] + [DefaultValue(null)] + public FPackageIndex Old; + + /// + /// The pointer serialized as an FFieldPath. Used in versions newer than . + /// + [JsonProperty] + [DefaultValue(null)] + public FFieldPath New; + + public bool ShouldSerializeOld() + { + return Old != null; + } + + public bool ShouldSerializeNew() + { + return New != null; + } + + public KismetPropertyPointer(FPackageIndex older) + { + Old = older; + } + + public KismetPropertyPointer(FFieldPath newer) + { + New = newer; + } + + public KismetPropertyPointer() + { + + } + } +} diff --git a/Translation/UAssetAPI/Kismet/KismetSerializer.cs b/Translation/UAssetAPI/Kismet/KismetSerializer.cs new file mode 100644 index 0000000..5a51451 --- /dev/null +++ b/Translation/UAssetAPI/Kismet/KismetSerializer.cs @@ -0,0 +1,1346 @@ +using Newtonsoft.Json.Linq; +using UAssetAPI.FieldTypes; +using UAssetAPI.Kismet.Bytecode.Expressions; +using UAssetAPI.Kismet.Bytecode; +using System; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.Kismet +{ + public static class KismetSerializer + { + public static UAsset asset; + public struct FSimpleMemberReference + { + public string MemberParent; + public string MemberName; + public Guid MemberGuid; + } + + public struct FEdGraphTerminalType + { + public string TerminalCategory; + public string TerminalSubCategory; + public string TerminalSubCategoryObject; + public bool bTerminalIsConst; + public bool bTerminalIsWeakPointer; + public bool bTerminalIsUObjectWrapper; + } + + public struct FEdGraphPinType + { + public string PinCategory; + public string PinSubCategory; + public string PinSubCategoryObject; + public FSimpleMemberReference PinSubCategoryMemberReference; + public FEdGraphTerminalType PinValueType; + public EPinContainerType ContainerType; + + public bool bIsReference; + public bool bIsConst; + public bool bIsWeakPointer; + public bool bIsUObjectWrapper; + } + + public enum EPinContainerType : byte + { + None, + Array, + Set, + Map + }; + + const string PC_Boolean = "Bool"; + const string PC_Byte = "Byte"; + const string PC_Class = "Class"; + const string PC_Int = "Int"; + const string PC_Int64 = "Int64"; + const string PC_Float = "Float"; + const string PC_Name = "Name"; + const string PC_Delegate = "Delegate"; + const string PC_MCDelegate = "mcdelegate"; + const string PC_Object = "Object"; + const string PC_Interface = "Interface"; + const string PC_String = "String"; + const string PC_Text = "Text"; + const string PC_Struct = "Struct"; + const string PC_Enum = "Enum"; + const string PC_SoftObject = "Softobject"; + const string PC_SoftClass = "Softclass"; + const string PC_None = "None"; + + public static JArray SerializeScript(KismetExpression[] code) + { + JArray jscript = new JArray(); + int index = 0; + foreach (KismetExpression instruction in code) + { + jscript.Add(SerializeExpression(instruction, ref index, true)); + } + + return jscript; + } + + public static string GetName(int index) + { + if (index > 0) + { + return asset.Exports[index - 1].ObjectName.ToString(); + } + else if (index < 0) + { + return asset.Imports[-index - 1].ObjectName.ToString(); + } + else + { + return ""; + } + } + + public static int GetClassIndex() + { + for (int i = 1; i <= asset.Exports.Count; i++) + { + if (asset.Exports[i - 1] is ClassExport) + { + return i; + } + } + return 0; + } + + public static string GetFullName(int index, bool alt = false) + { + + if (index > 0) + { + if (asset.Exports[index - 1].OuterIndex.Index != 0) + { + string parent = GetFullName(asset.Exports[index - 1].OuterIndex.Index); + return parent + "." + asset.Exports[index - 1].ObjectName.ToString(); + } + else + { + return asset.Exports[index - 1].ObjectName.ToString(); + } + + } + else if (index < 0) + { + + if (asset.Imports[-index - 1].OuterIndex.Index != 0) + { + string parent = GetFullName(asset.Imports[-index - 1].OuterIndex.Index); + return parent + "." + asset.Imports[-index - 1].ObjectName.ToString(); + } + else + { + return asset.Imports[-index - 1].ObjectName.ToString(); + } + + } + else + { + return ""; + } + } + + public static string GetParentName(int index) + { + if (index > 0) + { + if (asset.Exports[index - 1].OuterIndex.Index != 0) + { + string parent = GetFullName(asset.Exports[index - 1].OuterIndex.Index); + return parent; + } + else + { + return ""; + } + + } + else if (index < 0) + { + + if (asset.Imports[-index - 1].OuterIndex.Index != 0) + { + string parent = GetFullName(asset.Imports[-index - 1].OuterIndex.Index); + return parent; + } + else + { + return ""; + } + + } + else + { + return ""; + } + } + + public static bool FindProperty(int index, FName propname, out FProperty property) + { + if (index < 0) + { + + property = new FObjectProperty(); + return false; + + } + Export export = asset.Exports[index - 1]; + if (export is StructExport) + { + foreach (FProperty prop in (export as StructExport).LoadedProperties) + { + if (prop.Name == propname) + { + property = prop; + return true; + } + } + } + property = new FObjectProperty(); + return false; + } + + public static FEdGraphPinType GetPropertyCategoryInfo(FProperty prop) + { + FEdGraphPinType pin = new FEdGraphPinType(); + switch (prop) + { + case FInterfaceProperty finterface: + { + pin.PinCategory = PC_Interface; + pin.PinSubCategoryObject = GetFullName(finterface.InterfaceClass.Index); + break; + }; + case FClassProperty fclassprop: + { + pin.PinCategory = PC_Class; + pin.PinSubCategoryObject = GetFullName(fclassprop.MetaClass.Index); + break; + }; + case FSoftClassProperty fsoftclassprop: + { + pin.PinCategory = PC_SoftClass; + pin.PinSubCategoryObject = GetFullName(fsoftclassprop.MetaClass.Index); + break; + }; + case FSoftObjectProperty fsoftobjprop: + { + pin.PinCategory = PC_SoftObject; + pin.PinSubCategoryObject = GetFullName(fsoftobjprop.PropertyClass.Index); + break; + }; + case FObjectProperty fobjprop: + { + pin.PinCategory = PC_Object; + pin.PinSubCategoryObject = GetFullName(fobjprop.PropertyClass.Index); + if (fobjprop.PropertyFlags.HasFlag(EPropertyFlags.CPF_AutoWeak)) + { + pin.bIsWeakPointer = true; + } + break; + }; + case FStructProperty fstruct: + { + pin.PinCategory = PC_Struct; + pin.PinSubCategoryObject = GetFullName(fstruct.Struct.Index); + break; + }; + case FByteProperty fbyte: + { + pin.PinCategory = PC_Byte; + pin.PinSubCategoryObject = GetFullName(fbyte.Enum.Index); + break; + }; + case FEnumProperty fenum: + { + if (!(fenum.UnderlyingProp is FByteProperty)) + { + break; + } + pin.PinCategory = PC_Byte; + pin.PinSubCategoryObject = GetFullName(fenum.Enum.Index); + break; + } + case FBoolProperty fbool: + { + pin.PinCategory = PC_Boolean; + break; + }; + case FGenericProperty fgeneric: + { + + switch (fgeneric.SerializedType.ToString()) + { + case "FloatProperty": + { + pin.PinCategory = PC_Float; + break; + } + case "Int64Property": + { + pin.PinCategory = PC_Int64; + break; + } + case "IntProperty": + { + pin.PinCategory = PC_Int; + break; + } + case "NameProperty": + { + pin.PinCategory = PC_Name; + break; + } + case "StrProperty": + { + pin.PinCategory = PC_String; + break; + } + case "TextProperty": + { + pin.PinCategory = PC_Text; + break; + } + default: break; + }; + break; + } + + default: break; + } + + return pin; + + } + + public static FSimpleMemberReference FillSimpleMemberReference(int index) + { + FSimpleMemberReference member = new FSimpleMemberReference(); + if (index > 0) + { + member.MemberName = asset.Exports[index - 1].ObjectName.ToString(); + member.MemberParent = GetName(asset.Exports[index - 1].OuterIndex.Index); + member.MemberGuid = asset.Exports[index - 1].PackageGuid; + } + else if (index < 0) + { + member.MemberName = asset.Imports[-index - 1].ObjectName.ToString(); + member.MemberParent = asset.Imports[-index - 1].ClassPackage.ToString(); + member.MemberGuid = new Guid("00000000000000000000000000000000"); + } + + return member; + + } + + public static JObject SerializeGraphPinType(FEdGraphPinType pin) + { + + JObject jpin = new JObject(); + jpin.Add("PinCategory", pin.PinCategory); + jpin.Add("PinSubCategory", pin.PinCategory); + if (pin.PinSubCategoryObject == "" || pin.PinSubCategoryObject == null) + { + + } + else { jpin.Add("PinSubCategoryObject", pin.PinSubCategoryObject); } + + if (pin.PinSubCategoryMemberReference.MemberName != null) + { + FSimpleMemberReference member = pin.PinSubCategoryMemberReference; + if (member.MemberGuid.Equals(new Guid("00000000000000000000000000000000"))) + { + } + else + { + JObject jmember = new JObject(); + if (member.MemberParent != "" || member.MemberParent != null) + { + jmember.Add("MemberParent", member.MemberParent); + } + jmember.Add("MemberName", member.MemberName); + jmember.Add("MemberGuid", member.MemberGuid); + jpin.Add("PinSubCategoryMemberReference", jmember); + } + } + + if (pin.ContainerType == EPinContainerType.Map) + { + FEdGraphTerminalType valuetype = pin.PinValueType; + JObject jvaluetype = new JObject(); + + jvaluetype.Add("TerminalCategory", valuetype.TerminalCategory); + if (valuetype.TerminalSubCategory == null || valuetype.TerminalSubCategory == "") + { + jvaluetype.Add("TerminalSubCategory", "None"); + } + else + { + jvaluetype.Add("TerminalSubCategory", valuetype.TerminalSubCategory); + } + if (valuetype.TerminalSubCategoryObject != "" && valuetype.TerminalSubCategoryObject != null) + { + jvaluetype.Add("TerminalSubCategoryObject", valuetype.TerminalSubCategoryObject); + } + jvaluetype.Add("TerminalIsConst", valuetype.bTerminalIsConst); + jvaluetype.Add("TerminalIsWeakPointer", valuetype.bTerminalIsWeakPointer); + jpin.Add("PinValueType", jvaluetype); + + } + + if (pin.ContainerType != EPinContainerType.None) + { + jpin.Add("ContainerType", (int)pin.ContainerType); + } + + if (pin.bIsReference) + { + jpin.Add("IsReference", pin.bIsReference); + } + if (pin.bIsConst) + { + jpin.Add("IsConst", pin.bIsConst); + } + if (pin.bIsWeakPointer) + { + jpin.Add("IsWeakPointer", pin.bIsWeakPointer); + } + return jpin; + + } + public static FEdGraphPinType ConvertPropertyToPinType(FProperty property) + { + FEdGraphPinType pin = new FEdGraphPinType(); + FProperty prop = property; + + if (property is FMapProperty) + { + prop = (property as FMapProperty).KeyProp; + pin.ContainerType = EPinContainerType.Map; + pin.bIsWeakPointer = false; + FEdGraphPinType temppin = GetPropertyCategoryInfo((property as FMapProperty).ValueProp); + pin.PinValueType.TerminalCategory = temppin.PinCategory; + pin.PinValueType.TerminalSubCategory = temppin.PinSubCategory; + pin.PinValueType.TerminalSubCategoryObject = temppin.PinSubCategoryObject; + + pin.PinValueType.bTerminalIsConst = temppin.bIsConst; + pin.PinValueType.bTerminalIsWeakPointer = temppin.bIsWeakPointer; + + } + else if (property is FSetProperty) + { + prop = (property as FSetProperty).ElementProp; + pin.ContainerType = EPinContainerType.Set; + } + else if (property is FArrayProperty) + { + prop = (property as FArrayProperty).Inner; + pin.ContainerType = EPinContainerType.Array; + } + pin.bIsReference = property.PropertyFlags.HasFlag(EPropertyFlags.CPF_OutParm) && property.PropertyFlags.HasFlag(EPropertyFlags.CPF_ReferenceParm); + pin.bIsConst = property.PropertyFlags.HasFlag(EPropertyFlags.CPF_ConstParm); + + + if (prop is FMulticastDelegateProperty) + { + pin.PinCategory = PC_MCDelegate; + pin.PinSubCategoryMemberReference = FillSimpleMemberReference((prop as FMulticastDelegateProperty).SignatureFunction.Index); + + } + else if (prop is FDelegateProperty) + { + pin.PinCategory = PC_Delegate; + pin.PinSubCategoryMemberReference = FillSimpleMemberReference((prop as FDelegateProperty).SignatureFunction.Index); + } + else + { + FEdGraphPinType temppin = GetPropertyCategoryInfo(prop); + pin.PinCategory = temppin.PinCategory; + pin.PinSubCategory = temppin.PinSubCategory; + pin.PinSubCategoryObject = temppin.PinSubCategoryObject; + pin.bIsWeakPointer = temppin.bIsWeakPointer; + + } + return pin; + } + + public static JProperty[] SerializePropertyPointer(KismetPropertyPointer pointer, string[] names) + { + + JProperty[] jproparray = new JProperty[names.Length]; + + FProperty property; + if (asset.EngineVersion >= KismetPropertyPointer.XFER_PROP_POINTER_SWITCH_TO_SERIALIZING_AS_FIELD_PATH_VERSION) + { + if (pointer != null && pointer.New.ResolvedOwner.Index != 0) + { + + if (FindProperty(pointer.New.ResolvedOwner.Index, pointer.New.Path[0], out property)) + { + FEdGraphPinType PropertyType = ConvertPropertyToPinType(property); + jproparray[0] = new JProperty(names[0], SerializeGraphPinType(PropertyType)); + } + else + { + jproparray[0] = new JProperty(names[0], "##NOT SERIALIZED##"); + } + if (names.Length > 1) + { + jproparray[1] = new JProperty(names[1], pointer.New.Path[0].ToString()); + } + + return jproparray; + + } + } + jproparray[0] = new JProperty(names[0], "##NOT SERIALIZED##"); + if (names.Length > 1) + { + jproparray[1] = new JProperty(names[1], "##NOT SERIALIZED##"); + } + return jproparray; + + } + + public static JObject SerializeExpression(KismetExpression expression, ref int index, bool addindex = false) + { + + int savedindex = index; + JObject jexp = new JObject(); + index++; + switch (expression) + { + case EX_PrimitiveCast exp: + { + jexp.Add("Inst", exp.Inst); + index++; + switch (exp.ConversionType) + { + + case ECastToken.InterfaceToBool: + { + jexp.Add("CastType", "InterfaceToBool"); + break; + } + case ECastToken.ObjectToBool: + { + jexp.Add("CastType", "ObjectToBool"); + break; + } + case ECastToken.ObjectToInterface: + { + jexp.Add("CastType", "ObjectToInterface"); + index += 8; + jexp.Add("InterfaceClass", "##NOT SERIALIZED##"); + break; + } + default: break; + } + jexp.Add("Expression", SerializeExpression(exp.Target, ref index)); + break; + } + case EX_SetSet exp: + { + jexp.Add("Inst", exp.Inst); + jexp.Add("LeftSideExpression", SerializeExpression(exp.SetProperty, ref index)); + JArray jparams = new JArray(); + + index += 4; + foreach (KismetExpression param in exp.Elements) + { + jparams.Add(SerializeExpression(param, ref index)); + } + index++; + jexp.Add("Values", jparams); + break; + } + case EX_SetConst exp: + { + index += 8; + jexp.Add("Inst", exp.Inst); + jexp.Add(SerializePropertyPointer(exp.InnerProperty, new[] { "InnerProperty" })); + + index += 4; + JArray jparams = new JArray(); + foreach (KismetExpression param in exp.Elements) + { + jparams.Add(SerializeExpression(param, ref index)); + } + index++; + jexp.Add("Values", jparams); + break; + } + case EX_SetMap exp: + { + jexp.Add("Inst", exp.Inst); + jexp.Add("LeftSideExpression", SerializeExpression(exp.MapProperty, ref index)); + + index += 4; + JArray jparams = new JArray(); + for (var j = 1; j <= exp.Elements.Length / 2; j++) + { + JObject jobject = new JObject(); + jobject.Add("Key", SerializeExpression(exp.Elements[2 * (j - 1)], ref index)); + jobject.Add("Value", SerializeExpression(exp.Elements[2 * (j - 1) + 1], ref index)); + jparams.Add(jobject); + } + index++; + jexp.Add("Values", jparams); + break; + } + case EX_MapConst exp: + { + jexp.Add("Inst", exp.Inst); + index += 8; + jexp.Add(SerializePropertyPointer(exp.KeyProperty, new[] { "KeyProperty" })); + jexp.Add(SerializePropertyPointer(exp.ValueProperty, new[] { "ValueProperty" })); + + index += 4; + JArray jparams = new JArray(); + for (var j = 1; j <= exp.Elements.Length / 2; j++) + { + JObject jobject = new JObject(); + jobject.Add("Key", SerializeExpression(exp.Elements[2 * (j - 1)], ref index)); + jobject.Add("Value", SerializeExpression(exp.Elements[2 * (j - 1) + 1], ref index)); + jparams.Add(jobject); + } + index++; + jexp.Add("Values", jparams); + break; + } + case EX_ObjToInterfaceCast exp: + { + jexp.Add("Inst", exp.Inst); + index += 8; + jexp.Add("InterfaceClass", GetFullName(exp.ClassPtr.Index)); + jexp.Add("Expression", SerializeExpression(exp.Target, ref index)); + break; + } + case EX_CrossInterfaceCast exp: + { + jexp.Add("Inst", exp.Inst); + index += 8; + jexp.Add("InterfaceClass", GetFullName(exp.ClassPtr.Index)); + jexp.Add("Expression", SerializeExpression(exp.Target, ref index)); + break; + } + case EX_InterfaceToObjCast exp: + { + jexp.Add("Inst", exp.Inst); + index += 8; + jexp.Add("ObjectClass", GetFullName(exp.ClassPtr.Index)); + jexp.Add("Expression", SerializeExpression(exp.Target, ref index)); + break; + } + case EX_Let exp: + { + jexp.Add("Inst", exp.Inst); + index += 8; + jexp.Add("Variable", SerializeExpression(exp.Variable, ref index)); + jexp.Add("Expression", SerializeExpression(exp.Expression, ref index)); + break; + } + case EX_LetObj exp: + { + jexp.Add("Inst", exp.Inst); + jexp.Add("Variable", SerializeExpression(exp.VariableExpression, ref index)); + jexp.Add("Expression", SerializeExpression(exp.AssignmentExpression, ref index)); + break; + } + case EX_LetWeakObjPtr exp: + { + jexp.Add("Inst", exp.Inst); + jexp.Add("Variable", SerializeExpression(exp.VariableExpression, ref index)); + jexp.Add("Expression", SerializeExpression(exp.AssignmentExpression, ref index)); + break; + } + case EX_LetBool exp: + { + jexp.Add("Inst", exp.Inst); + jexp.Add("Variable", SerializeExpression(exp.VariableExpression, ref index)); + jexp.Add("Expression", SerializeExpression(exp.AssignmentExpression, ref index)); + break; + } + case EX_LetValueOnPersistentFrame exp: + { + jexp.Add("Inst", exp.Inst); + index += 8; + jexp.Add(SerializePropertyPointer(exp.DestinationProperty, new[] { "PropertyType", "PropertyName" })); + jexp.Add("Expression", SerializeExpression(exp.AssignmentExpression, ref index)); + break; + } + case EX_StructMemberContext exp: + { + jexp.Add("Inst", exp.Inst); + index += 8; + jexp.Add(SerializePropertyPointer(exp.StructMemberExpression, new[] { "PropertyType", "PropertyName" })); + jexp.Add("StructExpression", SerializeExpression(exp.StructExpression, ref index)); + break; + } + case EX_LetDelegate exp: + { + jexp.Add("Inst", exp.Inst); + jexp.Add("Variable", SerializeExpression(exp.VariableExpression, ref index)); + jexp.Add("Expression", SerializeExpression(exp.AssignmentExpression, ref index)); + break; + } + case EX_LocalVirtualFunction exp: + { + jexp.Add("Inst", exp.Inst); + index += 12; + jexp.Add("FunctionName", exp.VirtualFunctionName.ToString()); + JArray jparams = new JArray(); + foreach (KismetExpression param in exp.Parameters) + { + jparams.Add(SerializeExpression(param, ref index)); + } + index++; + jexp.Add("Parameters", jparams); + break; + } + case EX_LocalFinalFunction exp: + { + jexp.Add("Inst", exp.Inst); + jexp.Add("Function", GetName(exp.StackNode.Index)); + index += 8; + JArray jparams = new JArray(); + foreach (KismetExpression param in exp.Parameters) + { + jparams.Add(SerializeExpression(param, ref index)); + } + index++; + jexp.Add("Parameters", jparams); + break; + } + case EX_LetMulticastDelegate exp: + { + jexp.Add("Inst", exp.Inst); + jexp.Add("Variable", SerializeExpression(exp.VariableExpression, ref index)); + jexp.Add("Expression", SerializeExpression(exp.AssignmentExpression, ref index)); + break; + } + case EX_ComputedJump exp: + { + jexp.Add("Inst", exp.Inst); + jexp.Add("OffsetExpression", SerializeExpression(exp.CodeOffsetExpression, ref index)); + break; + } + case EX_Jump exp: + { + jexp.Add("Inst", exp.Inst); + index += 4; + jexp.Add("Offset", exp.CodeOffset); + break; + } + case EX_LocalVariable exp: + { + jexp.Add("Inst", exp.Inst); + index += 8; + jexp.Add(SerializePropertyPointer(exp.Variable, new[] { "VariableType", "VariableName" })); + break; + } + case EX_DefaultVariable exp: + { + jexp.Add("Inst", exp.Inst); + index += 8; + jexp.Add(SerializePropertyPointer(exp.Variable, new[] { "VariableType", "VariableName" })); + break; + } + case EX_InstanceVariable exp: + { + jexp.Add("Inst", exp.Inst); + index += 8; + jexp.Add(SerializePropertyPointer(exp.Variable, new[] { "VariableType", "VariableName" })); + break; + } + case EX_LocalOutVariable exp: + { + jexp.Add("Inst", exp.Inst); + index += 8; + jexp.Add(SerializePropertyPointer(exp.Variable, new[] { "VariableType", "VariableName" })); + break; + } + case EX_InterfaceContext exp: + { + jexp.Add("Inst", exp.Inst); + jexp.Add("Expression", SerializeExpression(exp.InterfaceValue, ref index)); + break; + } + case EX_DeprecatedOp4A exp1: + case EX_Nothing exp2: + case EX_EndOfScript exp3: + case EX_IntZero exp4: + case EX_IntOne exp5: + case EX_True exp6: + case EX_False exp7: + case EX_NoObject exp8: + case EX_NoInterface exp9: + case EX_Self exp10: + { + jexp.Add("Inst", expression.Inst); + break; + } + case EX_Return exp: + { + jexp.Add("Inst", exp.Inst); + jexp.Add("Expression", SerializeExpression(exp.ReturnExpression, ref index)); + break; + } + case EX_CallMath exp: + { + jexp.Add("Inst", exp.Inst); + index += 8; + jexp.Add("Function", GetName(exp.StackNode.Index)); + jexp.Add("ContextClass", GetParentName(exp.StackNode.Index)); + JArray jparams = new JArray(); + foreach (KismetExpression param in exp.Parameters) + { + jparams.Add(SerializeExpression(param, ref index)); + } + index++; + jexp.Add("Parameters", jparams); + break; + } + case EX_CallMulticastDelegate exp: + { + jexp.Add("Inst", exp.Inst); + index += 8; + JObject jsign = new JObject(); + bool bIsSelfContext = GetClassIndex() == exp.StackNode.Index; + jsign.Add("IsSelfContext", bIsSelfContext); + jsign.Add("MemberParent", GetFullName(exp.StackNode.Index)); + jsign.Add("MemberName", GetName(exp.StackNode.Index)); + jexp.Add("DelegateSignatureFunction", jsign); + jexp.Add("Delegate", SerializeExpression(exp.Delegate, ref index)); + + JArray jparams = new JArray(); + foreach (KismetExpression param in exp.Parameters) + { + jparams.Add(SerializeExpression(param, ref index)); + } + index++; + jexp.Add("Parameters", jparams); + break; + } + case EX_FinalFunction exp: + { + jexp.Add("Inst", exp.Inst); + index += 8; + jexp.Add("Function", GetName(exp.StackNode.Index)); + JArray jparams = new JArray(); + foreach (KismetExpression param in exp.Parameters) + { + jparams.Add(SerializeExpression(param, ref index)); + } + index++; + jexp.Add("Parameters", jparams); + break; + } + case EX_VirtualFunction exp: + { + jexp.Add("Inst", exp.Inst); + index += 12; + jexp.Add("Function", exp.VirtualFunctionName.ToString()); + JArray jparams = new JArray(); + + foreach (KismetExpression param in exp.Parameters) + { + jparams.Add(SerializeExpression(param, ref index)); + } + index++; + jexp.Add("Parameters", jparams); + break; + } + //case EX_ClassContext: + //case EX_Context_FailSilent: { + case EX_Context exp: + { + + if (exp is EX_Context_FailSilent) + { + exp = exp as EX_Context_FailSilent; + } + else if (exp is EX_ClassContext) + { + exp = exp as EX_ClassContext; + } + else + { + } + jexp.Add("Inst", exp.Inst); + jexp.Add("Context", SerializeExpression(exp.ObjectExpression, ref index)); + index += 4; + jexp.Add("SkipOffsetForNull", exp.Offset); + index += 8; + jexp.Add(SerializePropertyPointer(exp.RValuePointer, new[] { "RValuePropertyType", "RValuePropertyName" })); + jexp.Add("Expression", SerializeExpression(exp.ContextExpression, ref index)); + break; + } + case EX_IntConst exp: + { + index += 4; + jexp.Add("Inst", exp.Inst); + jexp.Add("Value", exp.Value); + break; + } + case EX_SkipOffsetConst exp: + { + index += 4; + jexp.Add("Inst", exp.Inst); + jexp.Add("Value", exp.Value); + break; + } + case EX_FloatConst exp: + { + index += 4; + jexp.Add("Inst", exp.Inst); + jexp.Add("Value", exp.Value); + break; + } + case EX_StringConst exp: + { + jexp.Add("Inst", exp.Inst); + index += exp.Value.Length + 1; + jexp.Add("Value", exp.Value); + break; + } + case EX_UnicodeStringConst exp: + { + jexp.Add("Inst", exp.Inst); + index += 2 * (exp.Value.Length + 1); + jexp.Add("Value", exp.Value); + break; + } + case EX_TextConst exp: + { + jexp.Add("Inst", exp.Inst); + index++; + switch (exp.Value.TextLiteralType) + { + case EBlueprintTextLiteralType.Empty: + { + jexp.Add("TextLiteralType", "Empty"); + break; + } + case EBlueprintTextLiteralType.LocalizedText: + { + jexp.Add("TextLiteralType", "LocalizedText"); + jexp.Add("SourceString", ReadString(exp.Value.LocalizedSource, ref index)); + jexp.Add("LocalizationKey", ReadString(exp.Value.LocalizedKey, ref index)); + jexp.Add("LocalizationNamespace", ReadString(exp.Value.LocalizedNamespace, ref index)); + break; + } + case EBlueprintTextLiteralType.InvariantText: + { + jexp.Add("TextLiteralType", "InvariantText"); + jexp.Add("SourceString", ReadString(exp.Value.InvariantLiteralString, ref index)); + + break; + } + case EBlueprintTextLiteralType.LiteralString: + { + jexp.Add("TextLiteralType", "LiteralString"); + jexp.Add("SourceString", ReadString(exp.Value.LiteralString, ref index)); + break; + } + case EBlueprintTextLiteralType.StringTableEntry: + { + jexp.Add("TextLiteralType", "StringTableEntry"); + index += 8; + jexp.Add("TableId", ReadString(exp.Value.StringTableId, ref index)); + jexp.Add("TableKey", ReadString(exp.Value.StringTableKey, ref index)); + break; + } + default: + break; + } + break; + } + case EX_ObjectConst exp: + { + jexp.Add("Inst", exp.Inst); + index += 8; + jexp.Add("Object", GetFullName(exp.Value.Index)); + break; + } + case EX_SoftObjectConst exp: + { + jexp.Add("Inst", exp.Inst); + jexp.Add("Value", SerializeExpression(exp.Value, ref index)); + break; + } + case EX_NameConst exp: + { + jexp.Add("Inst", exp.Inst); + index += 12; + jexp.Add("Value", exp.Value.ToString()); + break; + } + case EX_RotationConst exp: + { + jexp.Add("Inst", exp.Inst); + index += 12; + jexp.Add("Pitch", exp.Pitch); + jexp.Add("Yaw", exp.Yaw); + jexp.Add("Roll", exp.Roll); + break; + } + case EX_VectorConst exp: + { + jexp.Add("Inst", exp.Inst); + index += 12; + jexp.Add("X", exp.Value.X); + jexp.Add("Y", exp.Value.Y); + jexp.Add("Z", exp.Value.Z); + break; + } + case EX_TransformConst exp: + { + jexp.Add("Inst", exp.Inst); + index += 40; + JObject jrot = new JObject(); + JObject jtrans = new JObject(); + JObject jscale = new JObject(); + + jrot.Add("X", exp.Value.Rotation.X); + jrot.Add("Y", exp.Value.Rotation.Y); + jrot.Add("Z", exp.Value.Rotation.Z); + jrot.Add("W", exp.Value.Rotation.W); + + jtrans.Add("X", exp.Value.Translation.X); + jtrans.Add("Y", exp.Value.Translation.Y); + jtrans.Add("Z", exp.Value.Translation.Z); + + jscale.Add("X", exp.Value.Scale3D.X); + jscale.Add("Y", exp.Value.Scale3D.Y); + jscale.Add("Z", exp.Value.Scale3D.Z); + + jexp.Add("Rotation", jrot); + jexp.Add("Translation", jtrans); + jexp.Add("Scale", jscale); + break; + } + case EX_StructConst exp: + { + jexp.Add("Inst", exp.Inst); + index += 8; + jexp.Add("Struct", GetFullName(exp.Struct.Index)); + + index += 4; + JObject jstruct = new JObject(); + int tempindex = 0; + foreach (KismetExpression param in exp.Value) + { + JArray jstructpart = new JArray(); + jstructpart.Add(SerializeExpression(param, ref index)); + jstruct.Add("Missing property name" + tempindex, jstructpart); + tempindex++; + } + index++; + jexp.Add("Properties", jstruct); + break; + } + case EX_SetArray exp: + { + jexp.Add("Inst", exp.Inst); + jexp.Add("LeftSideExpression", SerializeExpression(exp.AssigningProperty, ref index)); + JArray jparams = new JArray(); + foreach (KismetExpression param in exp.Elements) + { + jparams.Add(SerializeExpression(param, ref index)); + } + index++; + jexp.Add("Values", jparams); + break; + } + case EX_ArrayConst exp: + { + jexp.Add("Inst", exp.Inst); + index += 8; + jexp.Add(SerializePropertyPointer(exp.InnerProperty, new[] { "VariableType" })); + + index += 4; + JArray jparams = new JArray(); + foreach (KismetExpression param in exp.Elements) + { + jparams.Add(SerializeExpression(param, ref index)); + } + index++; + jexp.Add("Values", jparams); + break; + } + case EX_ByteConst exp: + { + jexp.Add("Inst", exp.Inst); + index++; + jexp.Add("Value", exp.Value); + break; + } + case EX_IntConstByte exp: + { + jexp.Add("Inst", exp.Inst); + index++; + jexp.Add("Value", exp.Value); + break; + } + case EX_Int64Const exp: + { + jexp.Add("Inst", exp.Inst); + index += 8; + jexp.Add("Value", exp.Value); + break; + } + case EX_UInt64Const exp: + { + jexp.Add("Inst", exp.Inst); + index += 8; + jexp.Add("Value", exp.Value); + break; + } + case EX_FieldPathConst exp: + { + jexp.Add("Inst", exp.Inst); + jexp.Add("Expression", SerializeExpression(exp.Value, ref index)); + break; + } + case EX_MetaCast exp: + { + jexp.Add("Inst", exp.Inst); + index += 8; + jexp.Add("Class", GetFullName(exp.ClassPtr.Index)); + jexp.Add("Expression", SerializeExpression(exp.TargetExpression, ref index)); + break; + } + case EX_DynamicCast exp: + { + jexp.Add("Inst", exp.Inst); + index += 8; + jexp.Add("Class", GetFullName(exp.ClassPtr.Index)); + jexp.Add("Expression", SerializeExpression(exp.TargetExpression, ref index)); + break; + } + case EX_JumpIfNot exp: + { + jexp.Add("Inst", exp.Inst); + index += 4; + jexp.Add("Offset", exp.CodeOffset); + jexp.Add("Condition", SerializeExpression(exp.BooleanExpression, ref index)); + break; + } + case EX_Assert exp: + { + jexp.Add("Inst", exp.Inst); + index += 3; + jexp.Add("LineNumber", exp.LineNumber); + jexp.Add("Debug", exp.DebugMode); + jexp.Add("Expression", SerializeExpression(exp.AssertExpression, ref index)); + break; + } + case EX_InstanceDelegate exp: + { + jexp.Add("Inst", exp.Inst); + index += 12; + jexp.Add("FunctionName", exp.FunctionName.ToString()); + break; + } + case EX_AddMulticastDelegate exp: + { + jexp.Add("Inst", exp.Inst); + jexp.Add("MulticastDelegate", SerializeExpression(exp.Delegate, ref index)); + jexp.Add("Delegate", SerializeExpression(exp.DelegateToAdd, ref index)); + break; + } + case EX_RemoveMulticastDelegate exp: + { + jexp.Add("Inst", exp.Inst); + jexp.Add("MulticastDelegate", SerializeExpression(exp.Delegate, ref index)); + jexp.Add("Delegate", SerializeExpression(exp.DelegateToAdd, ref index)); + break; + } + case EX_ClearMulticastDelegate exp: + { + jexp.Add("Inst", exp.Inst); + jexp.Add("MulticastDelegate", SerializeExpression(exp.DelegateToClear, ref index)); + break; + } + case EX_BindDelegate exp: + { + jexp.Add("Inst", exp.Inst); + index += 12; + jexp.Add("FunctionName", exp.FunctionName.ToString()); + jexp.Add("Delegate", SerializeExpression(exp.Delegate, ref index)); + jexp.Add("Object", SerializeExpression(exp.ObjectTerm, ref index)); + break; + } + case EX_PushExecutionFlow exp: + { + jexp.Add("Inst", exp.Inst); + index += 4; + jexp.Add("Offset", exp.PushingAddress); + break; + } + case EX_PopExecutionFlow exp: + { + jexp.Add("Inst", exp.Inst); + break; + } + case EX_PopExecutionFlowIfNot exp: + { + jexp.Add("Inst", exp.Inst); + jexp.Add("Condition", SerializeExpression(exp.BooleanExpression, ref index)); + break; + } + case EX_Breakpoint exp: + { + jexp.Add("Inst", exp.Inst); + break; + } + case EX_WireTracepoint exp: + { + jexp.Add("Inst", exp.Inst); + break; + } + case EX_InstrumentationEvent exp: + { + jexp.Add("Inst", exp.Inst); + index++; + switch (exp.EventType) + { + case EScriptInstrumentationType.Class: + jexp.Add("EventType", "Class"); + break; + case EScriptInstrumentationType.ClassScope: + jexp.Add("EventType", "ClassScope"); + break; + case EScriptInstrumentationType.Instance: + jexp.Add("EventType", "Instance"); + break; + case EScriptInstrumentationType.Event: + jexp.Add("EventType", "Event"); + break; + case EScriptInstrumentationType.InlineEvent: + { + index += 12; + jexp.Add("EventType", "InlineEvent"); + jexp.Add("EventName", exp.EventName.ToString()); + break; + } + case EScriptInstrumentationType.ResumeEvent: + jexp.Add("EventType", "ResumeEvent"); + break; + case EScriptInstrumentationType.PureNodeEntry: + jexp.Add("EventType", "PureNodeEntry"); + break; + case EScriptInstrumentationType.NodeDebugSite: + jexp.Add("EventType", "NodeDebugSite"); + break; + case EScriptInstrumentationType.NodeEntry: + jexp.Add("EventType", "NodeEntry"); + break; + case EScriptInstrumentationType.NodeExit: + jexp.Add("EventType", "NodeExit"); + break; + case EScriptInstrumentationType.PushState: + jexp.Add("EventType", "PushState"); + break; + case EScriptInstrumentationType.RestoreState: + jexp.Add("EventType", "RestoreState"); + break; + case EScriptInstrumentationType.ResetState: + jexp.Add("EventType", "ResetState"); + break; + case EScriptInstrumentationType.SuspendState: + jexp.Add("EventType", "SuspendState"); + break; + case EScriptInstrumentationType.PopState: + jexp.Add("EventType", "PopState"); + break; + case EScriptInstrumentationType.TunnelEndOfThread: + jexp.Add("EventType", "TunnelEndOfThread"); + break; + case EScriptInstrumentationType.Stop: + jexp.Add("EventType", "Stop"); + break; + default: + break; + } + break; + } + case EX_Tracepoint exp: + { + jexp.Add("Inst", exp.Inst); + break; + } + case EX_SwitchValue exp: + { + jexp.Add("Inst", exp.Inst); + index += 6; + + jexp.Add("Expression", SerializeExpression(exp.IndexTerm, ref index)); + jexp.Add("OffsetToSwitchEnd", exp.EndGotoOffset); + JArray jcases = new JArray(); + + for (var j = 0; j < exp.Cases.Length; j++) + { + JObject jcase = new JObject(); + jcase.Add("CaseValue", SerializeExpression(exp.Cases[j].CaseIndexValueTerm, ref index)); + index += 4; + jcase.Add("OffsetToNextCase", exp.Cases[j].NextOffset); + jcase.Add("CaseResult", SerializeExpression(exp.Cases[j].CaseTerm, ref index)); + jcases.Add(jcase); + } + + jexp.Add("Cases", jcases); + jexp.Add("DefaultResult", SerializeExpression(exp.DefaultTerm, ref index)); + + break; + } + case EX_ArrayGetByRef exp: + { + jexp.Add("Inst", exp.Inst); + jexp.Add("ArrayExpression", SerializeExpression(exp.ArrayVariable, ref index)); + jexp.Add("IndexExpression", SerializeExpression(exp.ArrayIndex, ref index)); + break; + } + default: + { + // This should never occur. + //checkf(0, TEXT("Unknown bytecode 0x%02X"), (uint8)Opcode); + break; + } + } + if (addindex) { jexp.Add("StatementIndex", savedindex); } + return jexp; + } + + public static string ReadString(KismetExpression expr, ref int index) + { + + string result = ""; + index++; + switch (expr) + { + case EX_StringConst exp: + { + result = exp.Value; + index += result.Length + 1; + break; + } + case EX_UnicodeStringConst exp: + { + result = exp.Value; + index += 2 * (result.Length + 1); + break; + } + default: + break; + } + return result; + } + } +} \ No newline at end of file diff --git a/Translation/UAssetAPI/MainSerializer.cs b/Translation/UAssetAPI/MainSerializer.cs new file mode 100644 index 0000000..01b242d --- /dev/null +++ b/Translation/UAssetAPI/MainSerializer.cs @@ -0,0 +1,313 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Text.RegularExpressions; +using UAssetAPI.FieldTypes; +using UAssetAPI.PropertyTypes.Objects; +using UAssetAPI.PropertyTypes.Structs; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI +{ + /// + /// An entry in the property type registry. Contains the class Type used for standard and struct property serialization. + /// + internal class RegistryEntry + { + internal Type PropertyType; + internal bool HasCustomStructSerialization; + + public RegistryEntry() + { + + } + } + + /// + /// The main serializer for most property types in UAssetAPI. + /// + public static class MainSerializer + { +#if DEBUG + private static PropertyData lastType; +#endif + + private static IDictionary _propertyTypeRegistry; + + /// + /// The property type registry. Maps serialized property names to their types. + /// + internal static IDictionary PropertyTypeRegistry + { + get + { + InitializePropertyTypeRegistry(); + return _propertyTypeRegistry; + } + set => _propertyTypeRegistry = value; // I hope you know what you're doing! + } + + private static IEnumerable GetDependentAssemblies(Assembly analyzedAssembly) + { + return AppDomain.CurrentDomain.GetAssemblies().Where(a => GetNamesOfAssembliesReferencedBy(a).Contains(analyzedAssembly.FullName)); + } + + public static IEnumerable GetNamesOfAssembliesReferencedBy(Assembly assembly) + { + return assembly.GetReferencedAssemblies().Select(assemblyName => assemblyName.FullName); + } + + private static Type registryParentDataType = typeof(PropertyData); + + /// + /// Initializes the property type registry. + /// + private static void InitializePropertyTypeRegistry() + { + if (_propertyTypeRegistry != null) return; + _propertyTypeRegistry = new Dictionary(); + + Assembly[] allDependentAssemblies = GetDependentAssemblies(registryParentDataType.Assembly).ToArray(); + Assembly[] allAssemblies = new Assembly[allDependentAssemblies.Length + 1]; + allAssemblies[0] = registryParentDataType.Assembly; + Array.Copy(allDependentAssemblies, 0, allAssemblies, 1, allDependentAssemblies.Length); + + for (int i = 0; i < allAssemblies.Length; i++) + { + Type[] allPropertyDataTypes = allAssemblies[i].GetTypes().Where(t => t.IsSubclassOf(registryParentDataType)).ToArray(); + for (int j = 0; j < allPropertyDataTypes.Length; j++) + { + Type currentPropertyDataType = allPropertyDataTypes[j]; + if (currentPropertyDataType == null || currentPropertyDataType.ContainsGenericParameters) continue; + + var testInstance = Activator.CreateInstance(currentPropertyDataType); + + FString returnedPropType = currentPropertyDataType.GetProperty("PropertyType")?.GetValue(testInstance, null) as FString; + if (returnedPropType == null) continue; + bool? returnedHasCustomStructSerialization = currentPropertyDataType.GetProperty("HasCustomStructSerialization")?.GetValue(testInstance, null) as bool?; + if (returnedHasCustomStructSerialization == null) continue; + bool? returnedShouldBeRegistered = currentPropertyDataType.GetProperty("ShouldBeRegistered")?.GetValue(testInstance, null) as bool?; + if (returnedShouldBeRegistered == null) continue; + + if ((bool)returnedShouldBeRegistered) + { + RegistryEntry res = new RegistryEntry(); + res.PropertyType = currentPropertyDataType; + res.HasCustomStructSerialization = (bool)returnedHasCustomStructSerialization; + _propertyTypeRegistry[returnedPropType.Value] = res; + } + } + } + + // Fetch the current git commit while we're here + UAPUtils.CurrentCommit = string.Empty; + } + + /// + /// Initializes the correct PropertyData class based off of serialized name, type, etc. + /// + /// The serialized type of this property. + /// The serialized name of this property. + /// The UAsset which this property is contained within. + /// The BinaryReader to read from. If left unspecified, you must call the method manually. + /// The length of this property on disk in bytes. + /// The duplication index of this property. + /// Does this property serialize its header in the current context? + /// A new PropertyData instance based off of the passed parameters. + public static PropertyData TypeToClass(FName type, FName name, UAsset asset, AssetBinaryReader reader = null, int leng = 0, int duplicationIndex = 0, bool includeHeader = true) + { + long startingOffset = 0; + if (reader != null) startingOffset = reader.BaseStream.Position; + + if (type.Value.Value == "None") return null; + + PropertyData data = null; + if (PropertyTypeRegistry.ContainsKey(type.Value.Value)) + { + data = (PropertyData)Activator.CreateInstance(PropertyTypeRegistry[type.Value.Value].PropertyType, name); + } + else + { +#if DEBUG + Debug.WriteLine("-----------"); + Debug.WriteLine("Parsing unknown type " + type.ToString()); + Debug.WriteLine("Length: " + leng); + if (reader != null) Debug.WriteLine("Pos: " + reader.BaseStream.Position); + Debug.WriteLine("Last type: " + lastType.PropertyType?.ToString()); + if (lastType is ArrayPropertyData) Debug.WriteLine("Last array's type was " + ((ArrayPropertyData)lastType).ArrayType?.ToString()); + if (lastType is StructPropertyData) Debug.WriteLine("Last struct's type was " + ((StructPropertyData)lastType).StructType?.ToString()); + if (lastType is MapPropertyData lastTypeMap) + { + if (lastTypeMap.Value.Count == 0) + { + Debug.WriteLine("Last map's key type was " + lastTypeMap.KeyType?.ToString()); + Debug.WriteLine("Last map's value type was " + lastTypeMap.ValueType?.ToString()); + } + else + { + Debug.WriteLine("Last map's key type was " + lastTypeMap.Value.Keys.ElementAt(0).PropertyType?.ToString()); + Debug.WriteLine("Last map's value type was " + lastTypeMap.Value[0].PropertyType?.ToString()); + } + } + Debug.WriteLine("-----------"); +#endif + if (leng > 0) + { + data = new UnknownPropertyData(name); + ((UnknownPropertyData)data).SetSerializingPropertyType(type.Value); + } + else + { + if (reader == null) throw new FormatException("Unknown property type: " + type.ToString() + " (on " + name.ToString() + ")"); + throw new FormatException("Unknown property type: " + type.ToString() + " (on " + name.ToString() + " at " + reader.BaseStream.Position + ")"); + } + } + +#if DEBUG + lastType = data; +#endif + + data.DuplicationIndex = duplicationIndex; + if (reader != null) + { + data.Read(reader, includeHeader, leng); + if (data.Offset == 0) data.Offset = startingOffset; // fallback + } + + return data; + } + + /// + /// Reads a property into memory. + /// + /// The BinaryReader to read from. The underlying stream should be at the position of the property to be read. + /// Does this property serialize its header in the current context? + /// The property read from disk. + public static PropertyData Read(AssetBinaryReader reader, bool includeHeader) + { + long startingOffset = reader.BaseStream.Position; + FName name = reader.ReadFName(); + if (name.Value.Value == "None") return null; + + FName type = reader.ReadFName(); + + int leng = reader.ReadInt32(); + int duplicationIndex = reader.ReadInt32(); + PropertyData result = TypeToClass(type, name, reader.Asset, reader, leng, duplicationIndex, includeHeader); + result.Offset = startingOffset; + return result; + } + + private static readonly Regex allNonLetters = new Regex("[^a-zA-Z]", RegexOptions.Compiled); + + /// + /// Reads an FProperty into memory. Primarily used as a part of serialization. + /// + /// The BinaryReader to read from. The underlying stream should be at the position of the FProperty to be read. + /// The FProperty read from disk. + public static FProperty ReadFProperty(AssetBinaryReader reader) + { + FName serializedType = reader.ReadFName(); + Type requestedType = Type.GetType("UAssetAPI.FieldTypes.F" + allNonLetters.Replace(serializedType.Value.Value, string.Empty)); + if (requestedType == null) requestedType = typeof(FGenericProperty); + var res = (FProperty)Activator.CreateInstance(requestedType); + res.SerializedType = serializedType; + res.Read(reader); + return res; + } + + /// + /// Serializes an FProperty from memory. + /// + /// The FProperty to serialize. + /// The BinaryWriter to serialize the FProperty to. + public static void WriteFProperty(FProperty prop, AssetBinaryWriter writer) + { + writer.Write(prop.SerializedType); + prop.Write(writer); + } + + /// + /// Reads a UProperty into memory. Primarily used as a part of serialization. + /// + /// The BinaryReader to read from. The underlying stream should be at the position of the UProperty to be read. + /// The type of UProperty to be read. + /// The FProperty read from disk. + public static UProperty ReadUProperty(AssetBinaryReader reader, FName serializedType) + { + return ReadUProperty(reader, Type.GetType("UAssetAPI.FieldTypes.U" + allNonLetters.Replace(serializedType.Value.Value, string.Empty))); + } + + /// + /// Reads a UProperty into memory. Primarily used as a part of serialization. + /// + /// The BinaryReader to read from. The underlying stream should be at the position of the UProperty to be read. + /// The type of UProperty to be read. + /// The FProperty read from disk. + public static UProperty ReadUProperty(AssetBinaryReader reader, Type requestedType) + { + if (requestedType == null) requestedType = typeof(UGenericProperty); + var res = (UProperty)Activator.CreateInstance(requestedType); + res.Read(reader); + return res; + } + + /// + /// Reads a UProperty into memory. Primarily used as a part of serialization. + /// + /// The BinaryReader to read from. The underlying stream should be at the position of the UProperty to be read. + /// The FProperty read from disk. + public static T ReadUProperty(AssetBinaryReader reader) where T : UProperty + { + var res = (UProperty)Activator.CreateInstance(typeof(T)); + res.Read(reader); + return (T)res; + } + + /// + /// Serializes a UProperty from memory. + /// + /// The UProperty to serialize. + /// The BinaryWriter to serialize the UProperty to. + public static void WriteUProperty(UProperty prop, AssetBinaryWriter writer) + { + prop.Write(writer); + } + + /// + /// Serializes a property from memory. + /// + /// The property to serialize. + /// The BinaryWriter to serialize the property to. + /// Does this property serialize its header in the current context? + /// The serial offset where the length of the property is stored. + public static int Write(PropertyData property, AssetBinaryWriter writer, bool includeHeader) + { + if (property == null) return 0; + + property.Offset = writer.BaseStream.Position; + writer.Write(property.Name); + if (property is UnknownPropertyData unknownProp) + { + writer.Write(new FName(writer.Asset, unknownProp.SerializingPropertyType)); + } + else + { + writer.Write(new FName(writer.Asset, property.PropertyType)); + } + int oldLoc = (int)writer.BaseStream.Position; + writer.Write((int)0); // initial length + writer.Write(property.DuplicationIndex); + int realLength = property.Write(writer, includeHeader); + int newLoc = (int)writer.BaseStream.Position; + + writer.Seek(oldLoc, SeekOrigin.Begin); + writer.Write(realLength); + writer.Seek(newLoc, SeekOrigin.Begin); + return oldLoc; + } + } +} diff --git a/Translation/UAssetAPI/Properties/AssemblyInfo.cs b/Translation/UAssetAPI/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..9646a8a --- /dev/null +++ b/Translation/UAssetAPI/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("UAssetAPI")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("UAssetAPI")] +[assembly: AssemblyCopyright("Copyright © Atenfyr 2022")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("178417ec-1177-413e-be85-c83aecd64279")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Translation/UAssetAPI/Properties/Resources.Designer.cs b/Translation/UAssetAPI/Properties/Resources.Designer.cs new file mode 100644 index 0000000..ff782e3 --- /dev/null +++ b/Translation/UAssetAPI/Properties/Resources.Designer.cs @@ -0,0 +1,73 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace UAssetAPI.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("UAssetAPI.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized resource of type System.Byte[]. + /// + internal static byte[] AC7Key { + get { + object obj = ResourceManager.GetObject("AC7Key", resourceCulture); + return ((byte[])(obj)); + } + } + } +} diff --git a/Translation/UAssetAPI/Properties/Resources.resx b/Translation/UAssetAPI/Properties/Resources.resx new file mode 100644 index 0000000..339f76a --- /dev/null +++ b/Translation/UAssetAPI/Properties/Resources.resx @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + ..\Resources\AC7Key.bin;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/Translation/UAssetAPI/PropertyTypes/Objects/ArrayPropertyData.cs b/Translation/UAssetAPI/PropertyTypes/Objects/ArrayPropertyData.cs new file mode 100644 index 0000000..7793d71 --- /dev/null +++ b/Translation/UAssetAPI/PropertyTypes/Objects/ArrayPropertyData.cs @@ -0,0 +1,192 @@ +using Newtonsoft.Json; +using System; +using System.IO; +using UAssetAPI.PropertyTypes.Structs; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.PropertyTypes.Objects +{ + /// + /// Describes an array. + /// + public class ArrayPropertyData : PropertyData // Array + { + [JsonProperty] + public FName ArrayType; + [JsonProperty] + public StructPropertyData DummyStruct; + + internal bool ShouldSerializeStructsDifferently = true; + + public bool ShouldSerializeDummyStruct() + { + return Value.Length == 0; + } + + public ArrayPropertyData(FName name) : base(name) + { + Value = new PropertyData[0]; + } + + public ArrayPropertyData() + { + Value = new PropertyData[0]; + } + + private static readonly FString CurrentPropertyType = new FString("ArrayProperty"); + public override FString PropertyType { get { return CurrentPropertyType; } } + + public override void Read(AssetBinaryReader reader, bool includeHeader, long leng1, long leng2 = 0) + { + if (includeHeader) + { + ArrayType = reader.ReadFName(); + PropertyGuid = reader.ReadPropertyGuid(); + } + + int numEntries = reader.ReadInt32(); + if (ArrayType.Value.Value == "StructProperty" && ShouldSerializeStructsDifferently) + { + var results = new PropertyData[numEntries]; + + FName name = this.Name; + long structLength = 1; + FName fullType = FName.DefineDummy(reader.Asset, "Generic"); + Guid structGUID = new Guid(); + + if (reader.Asset.EngineVersion >= UE4Version.VER_UE4_INNER_ARRAY_TAG_INFO) + { + name = reader.ReadFName(); + if (name.Value.Value.Equals("None")) + { + Value = results; + return; + } + + FName thisArrayType = reader.ReadFName(); + if (thisArrayType.Value.Value.Equals("None")) + { + Value = results; + return; + } + + if (thisArrayType.Value.Value != ArrayType.Value.Value) throw new FormatException("Invalid array type: " + thisArrayType.ToString() + " vs " + ArrayType.ToString()); + + structLength = reader.ReadInt64(); // length value + fullType = reader.ReadFName(); + structGUID = new Guid(reader.ReadBytes(16)); + reader.ReadPropertyGuid(); + } + + if (numEntries == 0) + { + DummyStruct = new StructPropertyData(name, fullType) + { + StructGUID = structGUID + }; + } + else + { + for (int i = 0; i < numEntries; i++) + { + var data = new StructPropertyData(name, fullType); + data.Offset = reader.BaseStream.Position; + data.Read(reader, false, structLength); + data.StructGUID = structGUID; + results[i] = data; + } + DummyStruct = (StructPropertyData)results[0]; + } + Value = results; + } + else + { + var results = new PropertyData[numEntries]; + if (numEntries > 0) + { + int averageSizeEstimate1 = (int)(leng1 / numEntries); + int averageSizeEstimate2 = (int)((leng1 - 4) / numEntries); + for (int i = 0; i < numEntries; i++) + { + results[i] = MainSerializer.TypeToClass(ArrayType, FName.DefineDummy(reader.Asset, i.ToString(), int.MinValue), reader.Asset); + results[i].Offset = reader.BaseStream.Position; + if (results[i] is StructPropertyData) ((StructPropertyData)results[i]).StructType = FName.DefineDummy(reader.Asset, "Generic"); + results[i].Read(reader, false, averageSizeEstimate1, averageSizeEstimate2); + } + } + Value = results; + } + } + + public override int Write(AssetBinaryWriter writer, bool includeHeader) + { + if (Value.Length > 0) ArrayType = new FName(writer.Asset, Value[0].PropertyType); + + if (includeHeader) + { + writer.Write(ArrayType); + writer.WritePropertyGuid(PropertyGuid); + } + + int here = (int)writer.BaseStream.Position; + writer.Write(Value.Length); + if (ArrayType.Value.Value == "StructProperty" && ShouldSerializeStructsDifferently) + { + if (Value.Length == 0 && DummyStruct == null) throw new InvalidOperationException("No dummy struct present in an empty StructProperty array, cannot serialize"); + if (Value.Length > 0) DummyStruct = (StructPropertyData)Value[0]; + + FName fullType = DummyStruct.StructType; + + int lengthLoc = -1; + if (writer.Asset.EngineVersion >= UE4Version.VER_UE4_INNER_ARRAY_TAG_INFO) + { + writer.Write(DummyStruct.Name); + writer.Write(new FName(writer.Asset, "StructProperty")); + lengthLoc = (int)writer.BaseStream.Position; + writer.Write((long)0); + writer.Write(fullType); + if (writer.Asset.EngineVersion >= UE4Version.VER_UE4_STRUCT_GUID_IN_PROPERTY_TAG) writer.Write(DummyStruct.StructGUID.ToByteArray()); + if (writer.Asset.EngineVersion >= UE4Version.VER_UE4_PROPERTY_GUID_IN_PROPERTY_TAG) writer.Write((byte)0); + } + + for (int i = 0; i < Value.Length; i++) + { + ((StructPropertyData)Value[i]).StructType = fullType; + Value[i].Offset = writer.BaseStream.Position; + Value[i].Write(writer, false); + } + + if (writer.Asset.EngineVersion >= UE4Version.VER_UE4_INNER_ARRAY_TAG_INFO) + { + int fullLen = (int)writer.BaseStream.Position - lengthLoc; + int newLoc = (int)writer.BaseStream.Position; + writer.Seek(lengthLoc, SeekOrigin.Begin); + writer.Write(fullLen - 32 - (includeHeader ? 1 : 0)); + writer.Seek(newLoc, SeekOrigin.Begin); + } + } + else + { + for (int i = 0; i < Value.Length; i++) + { + Value[i].Offset = writer.BaseStream.Position; + Value[i].Write(writer, false); + } + } + + return (int)writer.BaseStream.Position - here; + } + + public override void FromString(string[] d, UAsset asset) + { + if (d[4] != null) ArrayType = FName.FromString(asset, d[4]); + } + + protected override void HandleCloned(PropertyData res) + { + ArrayPropertyData cloningProperty = (ArrayPropertyData)res; + cloningProperty.ArrayType = (FName)this.ArrayType?.Clone(); + cloningProperty.DummyStruct = (StructPropertyData)this.DummyStruct?.Clone(); + } + } +} \ No newline at end of file diff --git a/Translation/UAssetAPI/PropertyTypes/Objects/BoolPropertyData.cs b/Translation/UAssetAPI/PropertyTypes/Objects/BoolPropertyData.cs new file mode 100644 index 0000000..0ae2036 --- /dev/null +++ b/Translation/UAssetAPI/PropertyTypes/Objects/BoolPropertyData.cs @@ -0,0 +1,53 @@ +using System; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.PropertyTypes.Objects +{ + /// + /// Describes a boolean (). + /// + public class BoolPropertyData : PropertyData + { + public BoolPropertyData(FName name) : base(name) + { + + } + + public BoolPropertyData() + { + + } + + private static readonly FString CurrentPropertyType = new FString("BoolProperty"); + public override FString PropertyType { get { return CurrentPropertyType; } } + + public override void Read(AssetBinaryReader reader, bool includeHeader, long leng1, long leng2 = 0) + { + Value = reader.ReadBoolean(); + if (includeHeader) + { + PropertyGuid = reader.ReadPropertyGuid(); + } + } + + public override int Write(AssetBinaryWriter writer, bool includeHeader) + { + writer.Write(Value); + if (includeHeader) + { + writer.WritePropertyGuid(PropertyGuid); + } + return 0; + } + + public override string ToString() + { + return Convert.ToString(Value); + } + + public override void FromString(string[] d, UAsset asset) + { + Value = d[0].Equals("1") || d[0].ToLowerInvariant().Equals("true"); + } + } +} \ No newline at end of file diff --git a/Translation/UAssetAPI/PropertyTypes/Objects/BytePropertyData.cs b/Translation/UAssetAPI/PropertyTypes/Objects/BytePropertyData.cs new file mode 100644 index 0000000..29ed5ba --- /dev/null +++ b/Translation/UAssetAPI/PropertyTypes/Objects/BytePropertyData.cs @@ -0,0 +1,157 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; +using System; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.PropertyTypes.Objects +{ + public enum BytePropertyType + { + Byte, + FName, + } + + /// + /// Describes a byte or an enumeration value. + /// + public class BytePropertyData : PropertyData + { + [JsonProperty] + [JsonConverter(typeof(StringEnumConverter))] + public BytePropertyType ByteType; + + [JsonProperty] + public FName EnumType; + [JsonProperty] + public byte Value; + [JsonProperty] + public FName EnumValue; + + public bool ShouldSerializeValue() + { + return ByteType == BytePropertyType.Byte; + } + + public bool ShouldSerializeEnumValue() + { + return ByteType == BytePropertyType.FName; + } + + public BytePropertyData(FName name) : base(name) + { + + } + + public BytePropertyData() + { + + } + + private static readonly FString CurrentPropertyType = new FString("ByteProperty"); + public override FString PropertyType { get { return CurrentPropertyType; } } + + public override void Read(AssetBinaryReader reader, bool includeHeader, long leng1, long leng2 = 0) + { + ReadCustom(reader, includeHeader, leng1, leng2, true); + } + + private void ReadCustom(AssetBinaryReader reader, bool includeHeader, long leng1, long leng2, bool canRepeat) + { + if (includeHeader) + { + EnumType = reader.ReadFName(); + PropertyGuid = reader.ReadPropertyGuid(); + } + + switch (leng1) + { + case 1: + ByteType = BytePropertyType.Byte; + Value = reader.ReadByte(); + break; + case 0: // Should be only seen in maps; fallback "make our best guess and pray we're right" behavior + int nameMapPointer = reader.ReadInt32(); + int nameMapIndex = reader.ReadInt32(); + reader.BaseStream.Position -= sizeof(int) * 2; + + // In the case of it being serialized as just a byte, it will probably try to parse part of the next property and produce something too big for the name map + if (nameMapPointer < reader.Asset.GetNameMapIndexList().Count && nameMapIndex == 0 && !reader.Asset.GetNameReference(nameMapPointer).ToString().Contains("/")) + { + ByteType = BytePropertyType.FName; + EnumValue = reader.ReadFName(); + break; + } + else + { + ByteType = BytePropertyType.Byte; + Value = reader.ReadByte(); + break; + } + case 8: + ByteType = BytePropertyType.FName; + EnumValue = reader.ReadFName(); + break; + default: + if (canRepeat) + { + ReadCustom(reader, false, leng2, 0, false); + return; + } + throw new FormatException("Invalid length " + leng1 + " for ByteProperty"); + } + } + + public override int Write(AssetBinaryWriter writer, bool includeHeader) + { + if (includeHeader) + { + writer.Write(EnumType); + writer.WritePropertyGuid(PropertyGuid); + } + + switch (ByteType) + { + case BytePropertyType.Byte: + writer.Write((byte)Value); + return 1; + case BytePropertyType.FName: + writer.Write(EnumValue); + return 8; + default: + throw new FormatException("Invalid BytePropertyType " + ByteType); + } + } + + public FName GetEnumBase() + { + return EnumType; + } + + public FName GetEnumFull() + { + return EnumValue; + } + + public override string ToString() + { + if (ByteType == BytePropertyType.Byte) return Convert.ToString(Value); + //return GetEnumFull().Value; + return Value.ToString(); + } + + public override void FromString(string[] d, UAsset asset) + { + EnumType = FName.FromString(asset, d[0]); + if (byte.TryParse(d[1], out byte res)) + { + ByteType = BytePropertyType.Byte; + Value = res; + } + else + { + ByteType = BytePropertyType.FName; + EnumValue = FName.FromString(asset, d[1]); + } + } + } +} \ No newline at end of file diff --git a/Translation/UAssetAPI/PropertyTypes/Objects/DelegatePropertyData.cs b/Translation/UAssetAPI/PropertyTypes/Objects/DelegatePropertyData.cs new file mode 100644 index 0000000..351f02e --- /dev/null +++ b/Translation/UAssetAPI/PropertyTypes/Objects/DelegatePropertyData.cs @@ -0,0 +1,89 @@ +using Newtonsoft.Json; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.PropertyTypes.Objects +{ + /// + /// Describes a function bound to an Object. + /// + [JsonObject(MemberSerialization.OptIn)] + public class FDelegate + { + /** Uncertain what this is for; if you find out, please let me know */ + [JsonProperty] + public FPackageIndex Object; + /** Uncertain what this is for; if you find out, please let me know */ + [JsonProperty] + public FName Delegate; + + public FDelegate(FPackageIndex _object, FName @delegate) + { + Object = _object; + Delegate = @delegate; + } + + public FDelegate() + { + + } + } + + /// + /// Describes a function bound to an Object. + /// + public class DelegatePropertyData : PropertyData + { + public DelegatePropertyData(FName name) : base(name) + { + + } + + public DelegatePropertyData() + { + + } + + private static readonly FString CurrentPropertyType = new FString("DelegateProperty"); + public override FString PropertyType { get { return CurrentPropertyType; } } + + public override void Read(AssetBinaryReader reader, bool includeHeader, long leng1, long leng2 = 0) + { + if (includeHeader) + { + PropertyGuid = reader.ReadPropertyGuid(); + } + + Value = new FDelegate(reader.XFER_OBJECT_POINTER(), reader.ReadFName()); + } + + public override int Write(AssetBinaryWriter writer, bool includeHeader) + { + if (includeHeader) + { + writer.WritePropertyGuid(PropertyGuid); + } + + writer.XFERPTR(Value.Object); + writer.Write(Value.Delegate); + + return sizeof(int) * 3; + } + + public override string ToString() + { + return null; + } + + public override void FromString(string[] d, UAsset asset) + { + + } + + protected override void HandleCloned(PropertyData res) + { + DelegatePropertyData cloningProperty = (DelegatePropertyData)res; + + cloningProperty.Value = new FDelegate(this.Value.Object, this.Value.Delegate); + } + } +} \ No newline at end of file diff --git a/Translation/UAssetAPI/PropertyTypes/Objects/DoublePropertyData.cs b/Translation/UAssetAPI/PropertyTypes/Objects/DoublePropertyData.cs new file mode 100644 index 0000000..0acb867 --- /dev/null +++ b/Translation/UAssetAPI/PropertyTypes/Objects/DoublePropertyData.cs @@ -0,0 +1,65 @@ +using Newtonsoft.Json; +using System; +using UAssetAPI.JSON; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.PropertyTypes.Objects +{ + /// + /// Describes an IEEE 64-bit floating point variable (). + /// + public class DoublePropertyData : PropertyData + { + /// + /// The double that this property represents. + /// + [JsonProperty] + [JsonConverter(typeof(FSignedZeroJsonConverter))] + public double Value; + + public DoublePropertyData(FName name) : base(name) + { + + } + + public DoublePropertyData() + { + + } + + private static readonly FString CurrentPropertyType = new FString("DoubleProperty"); + public override FString PropertyType { get { return CurrentPropertyType; } } + + public override void Read(AssetBinaryReader reader, bool includeHeader, long leng1, long leng2 = 0) + { + if (includeHeader) + { + PropertyGuid = reader.ReadPropertyGuid(); + } + + Value = reader.ReadDouble(); + } + + public override int Write(AssetBinaryWriter writer, bool includeHeader) + { + if (includeHeader) + { + writer.WritePropertyGuid(PropertyGuid); + } + + writer.Write(Value); + return sizeof(double); + } + + public override string ToString() + { + return Convert.ToString(Value); + } + + public override void FromString(string[] d, UAsset asset) + { + Value = 0; + if (double.TryParse(d[0], out double res)) Value = res; + } + } +} \ No newline at end of file diff --git a/Translation/UAssetAPI/PropertyTypes/Objects/EnumPropertyData.cs b/Translation/UAssetAPI/PropertyTypes/Objects/EnumPropertyData.cs new file mode 100644 index 0000000..f494f94 --- /dev/null +++ b/Translation/UAssetAPI/PropertyTypes/Objects/EnumPropertyData.cs @@ -0,0 +1,81 @@ +using Newtonsoft.Json; +using System.IO; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.PropertyTypes.Objects +{ + /// + /// Describes an enumeration value. + /// + public class EnumPropertyData : PropertyData + { + [JsonProperty] + public FName EnumType; + + public EnumPropertyData(FName name) : base(name) + { + + } + + public EnumPropertyData() + { + + } + + private static readonly FString CurrentPropertyType = new FString("EnumProperty"); + public override FString PropertyType { get { return CurrentPropertyType; } } + + public override void Read(AssetBinaryReader reader, bool includeHeader, long leng1, long leng2 = 0) + { + if (includeHeader) + { + EnumType = reader.ReadFName(); + PropertyGuid = reader.ReadPropertyGuid(); + } + Value = reader.ReadFName(); + } + + public override int Write(AssetBinaryWriter writer, bool includeHeader) + { + if (includeHeader) + { + writer.Write(EnumType); + writer.WritePropertyGuid(PropertyGuid); + } + writer.Write(Value); + return sizeof(int) * 2; + } + + public override string ToString() + { + return Value.ToString(); + } + + public override void FromString(string[] d, UAsset asset) + { + if (d[0] != "null" && d[0] != null) + { + EnumType = FName.FromString(asset, d[0]); + } + else + { + EnumType = null; + } + + if (d[1] != "null" && d[1] != null) + { + Value = FName.FromString(asset, d[1]); + } + else + { + Value = null; + } + } + + protected override void HandleCloned(PropertyData res) + { + EnumPropertyData cloningProperty = (EnumPropertyData)res; + cloningProperty.EnumType = (FName)this.EnumType?.Clone(); + } + } +} \ No newline at end of file diff --git a/Translation/UAssetAPI/PropertyTypes/Objects/FloatPropertyData.cs b/Translation/UAssetAPI/PropertyTypes/Objects/FloatPropertyData.cs new file mode 100644 index 0000000..6d63395 --- /dev/null +++ b/Translation/UAssetAPI/PropertyTypes/Objects/FloatPropertyData.cs @@ -0,0 +1,65 @@ +using Newtonsoft.Json; +using System; +using UAssetAPI.JSON; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.PropertyTypes.Objects +{ + /// + /// Describes an IEEE 32-bit floating point variable (). + /// + public class FloatPropertyData : PropertyData + { + /// + /// The float that this property represents. + /// + [JsonProperty] + [JsonConverter(typeof(FSignedZeroJsonConverter))] + public float Value; + + public FloatPropertyData(FName name) : base(name) + { + + } + + public FloatPropertyData() + { + + } + + private static readonly FString CurrentPropertyType = new FString("FloatProperty"); + public override FString PropertyType { get { return CurrentPropertyType; } } + + public override void Read(AssetBinaryReader reader, bool includeHeader, long leng1, long leng2 = 0) + { + if (includeHeader) + { + PropertyGuid = reader.ReadPropertyGuid(); + } + + Value = reader.ReadSingle(); + } + + public override int Write(AssetBinaryWriter writer, bool includeHeader) + { + if (includeHeader) + { + writer.WritePropertyGuid(PropertyGuid); + } + + writer.Write(Value); + return sizeof(float); + } + + public override string ToString() + { + return Convert.ToString(Value); + } + + public override void FromString(string[] d, UAsset asset) + { + Value = 0; + if (float.TryParse(d[0], out float res)) Value = res; + } + } +} \ No newline at end of file diff --git a/Translation/UAssetAPI/PropertyTypes/Objects/Int16PropertyData.cs b/Translation/UAssetAPI/PropertyTypes/Objects/Int16PropertyData.cs new file mode 100644 index 0000000..fb0fbfd --- /dev/null +++ b/Translation/UAssetAPI/PropertyTypes/Objects/Int16PropertyData.cs @@ -0,0 +1,57 @@ +using System; +using System.IO; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.PropertyTypes.Objects +{ + /// + /// Describes a 16-bit signed integer variable (). + /// + public class Int16PropertyData : PropertyData + { + public Int16PropertyData(FName name) : base(name) + { + + } + + public Int16PropertyData() + { + + } + + private static readonly FString CurrentPropertyType = new FString("Int16Property"); + public override FString PropertyType { get { return CurrentPropertyType; } } + + public override void Read(AssetBinaryReader reader, bool includeHeader, long leng1, long leng2 = 0) + { + if (includeHeader) + { + PropertyGuid = reader.ReadPropertyGuid(); + } + + Value = reader.ReadInt16(); + } + + public override int Write(AssetBinaryWriter writer, bool includeHeader) + { + if (includeHeader) + { + writer.WritePropertyGuid(PropertyGuid); + } + + writer.Write(Value); + return sizeof(short); + } + + public override string ToString() + { + return Convert.ToString(Value); + } + + public override void FromString(string[] d, UAsset asset) + { + Value = 0; + if (short.TryParse(d[0], out short res)) Value = res; + } + } +} \ No newline at end of file diff --git a/Translation/UAssetAPI/PropertyTypes/Objects/Int64PropertyData.cs b/Translation/UAssetAPI/PropertyTypes/Objects/Int64PropertyData.cs new file mode 100644 index 0000000..c676279 --- /dev/null +++ b/Translation/UAssetAPI/PropertyTypes/Objects/Int64PropertyData.cs @@ -0,0 +1,57 @@ +using System; +using System.IO; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.PropertyTypes.Objects +{ + /// + /// Describes a 64-bit signed integer variable (). + /// + public class Int64PropertyData : PropertyData + { + public Int64PropertyData(FName name) : base(name) + { + + } + + public Int64PropertyData() + { + + } + + private static readonly FString CurrentPropertyType = new FString("Int64Property"); + public override FString PropertyType { get { return CurrentPropertyType; } } + + public override void Read(AssetBinaryReader reader, bool includeHeader, long leng1, long leng2 = 0) + { + if (includeHeader) + { + PropertyGuid = reader.ReadPropertyGuid(); + } + + Value = reader.ReadInt64(); + } + + public override int Write(AssetBinaryWriter writer, bool includeHeader) + { + if (includeHeader) + { + writer.WritePropertyGuid(PropertyGuid); + } + + writer.Write(Value); + return sizeof(long); + } + + public override string ToString() + { + return Convert.ToString(Value); + } + + public override void FromString(string[] d, UAsset asset) + { + Value = 0; + if (long.TryParse(d[0], out long res)) Value = res; + } + } +} \ No newline at end of file diff --git a/Translation/UAssetAPI/PropertyTypes/Objects/Int8PropertyData.cs b/Translation/UAssetAPI/PropertyTypes/Objects/Int8PropertyData.cs new file mode 100644 index 0000000..d154f15 --- /dev/null +++ b/Translation/UAssetAPI/PropertyTypes/Objects/Int8PropertyData.cs @@ -0,0 +1,57 @@ +using System; +using System.IO; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.PropertyTypes.Objects +{ + /// + /// Describes an 8-bit signed integer variable (). + /// + public class Int8PropertyData : PropertyData + { + public Int8PropertyData(FName name) : base(name) + { + + } + + public Int8PropertyData() + { + + } + + private static readonly FString CurrentPropertyType = new FString("Int8Property"); + public override FString PropertyType { get { return CurrentPropertyType; } } + + public override void Read(AssetBinaryReader reader, bool includeHeader, long leng1, long leng2 = 0) + { + if (includeHeader) + { + PropertyGuid = reader.ReadPropertyGuid(); + } + + Value = reader.ReadSByte(); + } + + public override int Write(AssetBinaryWriter writer, bool includeHeader) + { + if (includeHeader) + { + writer.WritePropertyGuid(PropertyGuid); + } + + writer.Write(Value); + return sizeof(sbyte); + } + + public override string ToString() + { + return Convert.ToString(Value); + } + + public override void FromString(string[] d, UAsset asset) + { + Value = 0; + if (sbyte.TryParse(d[0], out sbyte res)) Value = res; + } + } +} \ No newline at end of file diff --git a/Translation/UAssetAPI/PropertyTypes/Objects/IntPropertyData.cs b/Translation/UAssetAPI/PropertyTypes/Objects/IntPropertyData.cs new file mode 100644 index 0000000..b84b7c7 --- /dev/null +++ b/Translation/UAssetAPI/PropertyTypes/Objects/IntPropertyData.cs @@ -0,0 +1,57 @@ +using System; +using System.IO; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.PropertyTypes.Objects +{ + /// + /// Describes a 32-bit signed integer variable (). + /// + public class IntPropertyData : PropertyData + { + public IntPropertyData(FName name) : base(name) + { + + } + + public IntPropertyData() + { + + } + + private static readonly FString CurrentPropertyType = new FString("IntProperty"); + public override FString PropertyType { get { return CurrentPropertyType; } } + + public override void Read(AssetBinaryReader reader, bool includeHeader, long leng1, long leng2 = 0) + { + if (includeHeader) + { + PropertyGuid = reader.ReadPropertyGuid(); + } + + Value = reader.ReadInt32(); + } + + public override int Write(AssetBinaryWriter writer, bool includeHeader) + { + if (includeHeader) + { + writer.WritePropertyGuid(PropertyGuid); + } + + writer.Write(Value); + return sizeof(int); + } + + public override string ToString() + { + return Convert.ToString(Value); + } + + public override void FromString(string[] d, UAsset asset) + { + Value = 0; + if (int.TryParse(d[0], out int res)) Value = res; + } + } +} diff --git a/Translation/UAssetAPI/PropertyTypes/Objects/MapPropertyData.cs b/Translation/UAssetAPI/PropertyTypes/Objects/MapPropertyData.cs new file mode 100644 index 0000000..630540d --- /dev/null +++ b/Translation/UAssetAPI/PropertyTypes/Objects/MapPropertyData.cs @@ -0,0 +1,198 @@ +using Newtonsoft.Json; +using System.Collections.Specialized; +using System.Linq; +using UAssetAPI.JSON; +using UAssetAPI.PropertyTypes.Structs; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.PropertyTypes.Objects +{ + /// + /// Describes a map (). + /// + public class MapPropertyData : PropertyData + { + /// + /// The map that this property represents. + /// + [JsonProperty] + [JsonConverter(typeof(TMapJsonConverter))] + public TMap Value; + + /// + /// Used when the length of the map is zero. + /// ] + [JsonProperty] + public FName KeyType; + + /// + /// Used when the length of the map is zero. + /// + [JsonProperty] + public FName ValueType; + + public bool ShouldSerializeKeyType() + { + return Value.Count == 0; + } + + public bool ShouldSerializeValueType() + { + return Value.Count == 0; + } + + [JsonProperty] + public PropertyData[] KeysToRemove = null; + + public MapPropertyData(FName name) : base(name) + { + Value = new TMap(); + } + + public MapPropertyData() + { + Value = new TMap(); + } + + private static readonly FString CurrentPropertyType = new FString("MapProperty"); + public override FString PropertyType { get { return CurrentPropertyType; } } + + private PropertyData MapTypeToClass(FName type, FName name, AssetBinaryReader reader, int leng, bool includeHeader, bool isKey) + { + switch (type.Value.Value) + { + case "StructProperty": + FName strucType = null; + + if (reader.Asset.MapStructTypeOverride.ContainsKey(name.Value.Value)) + { + if (isKey) + { + strucType = new FName(reader.Asset, reader.Asset.MapStructTypeOverride[name.Value.Value].Item1); + } + else + { + strucType = new FName(reader.Asset, reader.Asset.MapStructTypeOverride[name.Value.Value].Item2); + } + } + + if (strucType == null) strucType = FName.DefineDummy(reader.Asset, "Generic"); + + StructPropertyData data = new StructPropertyData(name, strucType); + data.Offset = reader.BaseStream.Position; + data.Read(reader, false, 1); + return data; + default: + var res = MainSerializer.TypeToClass(type, name, reader.Asset, null, leng); + res.Offset = reader.BaseStream.Position; + res.Read(reader, includeHeader, leng); + return res; + } + } + + private TMap ReadRawMap(AssetBinaryReader reader, FName type1, FName type2, int numEntries) + { + var resultingDict = new TMap(); + + PropertyData data1 = null; + PropertyData data2 = null; + for (int i = 0; i < numEntries; i++) + { + data1 = MapTypeToClass(type1, Name, reader, 0, false, true); + data2 = MapTypeToClass(type2, Name, reader, 0, false, false); + + resultingDict.Add(data1, data2); + } + + return resultingDict; + } + + public override void Read(AssetBinaryReader reader, bool includeHeader, long leng1, long leng2 = 0) + { + FName type1 = null, type2 = null; + if (includeHeader) + { + type1 = reader.ReadFName(); + type2 = reader.ReadFName(); + PropertyGuid = reader.ReadPropertyGuid(); + } + + int numKeysToRemove = reader.ReadInt32(); + KeysToRemove = new PropertyData[numKeysToRemove]; + for (int i = 0; i < numKeysToRemove; i++) + { + KeysToRemove[i] = MapTypeToClass(type1, Name, reader, 0, false, true); + } + + int numEntries = reader.ReadInt32(); + if (numEntries == 0) + { + KeyType = type1; + ValueType = type2; + } + Value = ReadRawMap(reader, type1, type2, numEntries); + } + + private void WriteRawMap(AssetBinaryWriter writer, TMap map) + { + foreach (var entry in map) + { + entry.Key.Offset = writer.BaseStream.Position; + entry.Key.Write(writer, false); + entry.Value.Offset = writer.BaseStream.Position; + entry.Value.Write(writer, false); + } + } + + public override int Write(AssetBinaryWriter writer, bool includeHeader) + { + if (includeHeader) + { + if (Value.Count > 0) + { + writer.Write(new FName(writer.Asset, Value.Keys.ElementAt(0).PropertyType)); + writer.Write(new FName(writer.Asset, Value[0].PropertyType)); + } + else + { + writer.Write(KeyType); + writer.Write(ValueType); + } + writer.WritePropertyGuid(PropertyGuid); + } + + int here = (int)writer.BaseStream.Position; + writer.Write(KeysToRemove?.Length ?? 0); + if (KeysToRemove != null) + { + for (int i = 0; i < KeysToRemove.Length; i++) + { + var entry = KeysToRemove[i]; + entry.Offset = writer.BaseStream.Position; + entry.Write(writer, false); + } + } + + writer.Write(Value.Count); + WriteRawMap(writer, Value); + return (int)writer.BaseStream.Position - here; + } + + protected override void HandleCloned(PropertyData res) + { + MapPropertyData cloningProperty = (MapPropertyData)res; + + var newDict = new TMap(); + foreach (var entry in this.Value) + { + newDict[(PropertyData)entry.Key.Clone()] = (PropertyData)entry.Value.Clone(); + } + cloningProperty.Value = newDict; + + cloningProperty.KeysToRemove = (PropertyData[])this.KeysToRemove.Clone(); + + cloningProperty.KeyType = (FName)this.KeyType.Clone(); + cloningProperty.ValueType = (FName)this.ValueType.Clone(); + } + } +} \ No newline at end of file diff --git a/Translation/UAssetAPI/PropertyTypes/Objects/MulticastDelegatePropertyData.cs b/Translation/UAssetAPI/PropertyTypes/Objects/MulticastDelegatePropertyData.cs new file mode 100644 index 0000000..9459814 --- /dev/null +++ b/Translation/UAssetAPI/PropertyTypes/Objects/MulticastDelegatePropertyData.cs @@ -0,0 +1,110 @@ +using Newtonsoft.Json; +using System; +using System.IO; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.PropertyTypes.Objects +{ + /// + /// Describes a function bound to an Object. + /// + [JsonObject(MemberSerialization.OptIn)] + public class FMulticastDelegate + { + /** Uncertain what this is for; if you find out, please let me know */ + [JsonProperty] + public int Number; + /** Uncertain what this is for; if you find out, please let me know */ + [JsonProperty] + public FName Delegate; + + public FMulticastDelegate(int number, FName @delegate) + { + Number = number; + Delegate = @delegate; + } + + public FMulticastDelegate() + { + + } + } + + /// + /// Describes a list of functions bound to an Object. + /// + public class MulticastDelegatePropertyData : PropertyData + { + public MulticastDelegatePropertyData(FName name) : base(name) + { + + } + + public MulticastDelegatePropertyData() + { + + } + + private static readonly FString CurrentPropertyType = new FString("MulticastDelegateProperty"); + public override FString PropertyType { get { return CurrentPropertyType; } } + + public override void Read(AssetBinaryReader reader, bool includeHeader, long leng1, long leng2 = 0) + { + if (includeHeader) + { + PropertyGuid = reader.ReadPropertyGuid(); + } + + int numVals = reader.ReadInt32(); + Value = new FMulticastDelegate[numVals]; + for (int i = 0; i < numVals; i++) + { + Value[i] = new FMulticastDelegate(reader.ReadInt32(), reader.ReadFName()); + } + } + + public override int Write(AssetBinaryWriter writer, bool includeHeader) + { + if (includeHeader) + { + writer.WritePropertyGuid(PropertyGuid); + } + + writer.Write(Value.Length); + for (int i = 0; i < Value.Length; i++) + { + writer.Write(Value[i].Number); + writer.Write(Value[i].Delegate); + } + return sizeof(int) + sizeof(int) * 3 * Value.Length; + } + + public override string ToString() + { + string oup = "("; + for (int i = 0; i < Value.Length; i++) + { + oup += "(" + Convert.ToString(Value[i].Number) + ", " + Value[i].Delegate.Value.Value + "), "; + } + return oup.Substring(0, oup.Length - 2) + ")"; + } + + public override void FromString(string[] d, UAsset asset) + { + + } + + protected override void HandleCloned(PropertyData res) + { + MulticastDelegatePropertyData cloningProperty = (MulticastDelegatePropertyData)res; + + FMulticastDelegate[] newData = new FMulticastDelegate[this.Value.Length]; + for (int i = 0; i < this.Value.Length; i++) + { + newData[i] = new FMulticastDelegate(this.Value[i].Number, (FName)this.Value[i].Delegate.Clone()); + } + + cloningProperty.Value = newData; + } + } +} \ No newline at end of file diff --git a/Translation/UAssetAPI/PropertyTypes/Objects/NamePropertyData.cs b/Translation/UAssetAPI/PropertyTypes/Objects/NamePropertyData.cs new file mode 100644 index 0000000..f9648c8 --- /dev/null +++ b/Translation/UAssetAPI/PropertyTypes/Objects/NamePropertyData.cs @@ -0,0 +1,55 @@ +using System.IO; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.PropertyTypes.Objects +{ + /// + /// Describes an . + /// + public class NamePropertyData : PropertyData + { + public NamePropertyData(FName name) : base(name) + { + + } + + public NamePropertyData() + { + + } + + private static readonly FString CurrentPropertyType = new FString("NameProperty"); + public override FString PropertyType { get { return CurrentPropertyType; } } + + public override void Read(AssetBinaryReader reader, bool includeHeader, long leng1, long leng2 = 0) + { + if (includeHeader) + { + PropertyGuid = reader.ReadPropertyGuid(); + } + + Value = reader.ReadFName(); + } + + public override int Write(AssetBinaryWriter writer, bool includeHeader) + { + if (includeHeader) + { + writer.WritePropertyGuid(PropertyGuid); + } + + writer.Write(Value); + return sizeof(int) * 2; + } + + public override string ToString() + { + return Value == null ? "null" : Value.ToString(); + } + + public override void FromString(string[] d, UAsset asset) + { + Value = FName.FromString(asset, d[0]); + } + } +} \ No newline at end of file diff --git a/Translation/UAssetAPI/PropertyTypes/Objects/ObjectPropertyData.cs b/Translation/UAssetAPI/PropertyTypes/Objects/ObjectPropertyData.cs new file mode 100644 index 0000000..b630d81 --- /dev/null +++ b/Translation/UAssetAPI/PropertyTypes/Objects/ObjectPropertyData.cs @@ -0,0 +1,108 @@ +using Newtonsoft.Json; +using System; +using System.IO; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.PropertyTypes.Objects +{ + /// + /// Describes a reference variable to another object (import/export) which may be null (). + /// + public class ObjectPropertyData : PropertyData + { + public ObjectPropertyData(FName name) : base(name) + { + + } + + public ObjectPropertyData() + { + + } + + private static readonly FString CurrentPropertyType = new FString("ObjectProperty"); + public override FString PropertyType { get { return CurrentPropertyType; } } + + /// + /// Returns true if this ObjectProperty represents an import. + /// + /// Is this ObjectProperty an import? + public bool IsImport() + { + return Value.IsImport(); + } + + /// + /// Returns true if this ObjectProperty represents an export. + /// + /// Is this ObjectProperty an export? + public bool IsExport() + { + return Value.IsExport(); + } + + /// + /// Return true if this ObjectProperty represents null (i.e. neither an import nor an export) + /// + /// Does this ObjectProperty represent null? + public bool IsNull() + { + return Value.IsNull(); + } + + /// + /// Check that this ObjectProperty is an import index and return the corresponding import. + /// + /// The import that this ObjectProperty represents in the import map. + /// Thrown when this is not an index into the import map. + public Import ToImport(UAsset asset) + { + return Value.ToImport(asset); + } + + /// + /// Check that this ObjectProperty is an export index and return the corresponding export. + /// + /// The export that this ObjectProperty represents in the the export map. + /// Thrown when this is not an index into the export map. + public Export ToExport(UAsset asset) + { + return Value.ToExport(asset); + } + + public override void Read(AssetBinaryReader reader, bool includeHeader, long leng1, long leng2 = 0) + { + if (includeHeader) + { + PropertyGuid = reader.ReadPropertyGuid(); + } + + Value = new FPackageIndex(reader.ReadInt32()); + } + + public override int Write(AssetBinaryWriter writer, bool includeHeader) + { + if (includeHeader) + { + writer.WritePropertyGuid(PropertyGuid); + } + + writer.Write(Value.Index); + return sizeof(int); + } + + public override string ToString() + { + return Value.ToString(); + } + + public override void FromString(string[] d, UAsset asset) + { + if (int.TryParse(d[0], out int res)) + { + Value = new FPackageIndex(res); + return; + } + } + } +} \ No newline at end of file diff --git a/Translation/UAssetAPI/PropertyTypes/Objects/PropertyData.cs b/Translation/UAssetAPI/PropertyTypes/Objects/PropertyData.cs new file mode 100644 index 0000000..e581521 --- /dev/null +++ b/Translation/UAssetAPI/PropertyTypes/Objects/PropertyData.cs @@ -0,0 +1,153 @@ +using Newtonsoft.Json; +using System; +using System.IO; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.PropertyTypes.Objects +{ + /// + /// Generic Unreal property class. + /// + [JsonObject(MemberSerialization.OptIn)] + public abstract class PropertyData : ICloneable + { + /// + /// The name of this property. + /// + [JsonProperty] + public FName Name = null; + + /// + /// The duplication index of this property. Used to distinguish properties with the same name in the same struct. + /// + [JsonProperty] + public int DuplicationIndex = 0; + + /// + /// An optional property GUID. Nearly always null. + /// + public Guid? PropertyGuid = null; + + /// + /// The offset of this property on disk. This is for the user only, and has no bearing in the API itself. + /// + public long Offset = -1; + + /// + /// An optional tag which can be set on any property in memory. This is for the user only, and has no bearing in the API itself. + /// + public object Tag; + + public object RawValue; + + public void SetObject(object value) + { + RawValue = value; + } + + public T GetObject() + { + if (RawValue is null) return default(T); + return (T)RawValue; + } + + public PropertyData(FName name) + { + Name = name; + } + + public PropertyData() + { + + } + + private static FString FallbackPropertyType = new FString(string.Empty); + /// + /// Determines whether or not this particular property should be registered in the property registry and automatically used when parsing assets. + /// + public virtual bool ShouldBeRegistered { get { return true; } } + /// + /// Determines whether or not this particular property has custom serialization within a StructProperty. + /// + public virtual bool HasCustomStructSerialization { get { return false; } } + /// + /// The type of this property as an FString. + /// + public virtual FString PropertyType { get { return FallbackPropertyType; } } + + /// + /// Reads out a property from a BinaryReader. + /// + /// The BinaryReader to read from. + /// Whether or not to also read the "header" of the property, which is data considered by the Unreal Engine to be data that is part of the PropertyData base class rather than any particular child class. + /// An estimate for the length of the data being read out. + /// A second estimate for the length of the data being read out. + public virtual void Read(AssetBinaryReader reader, bool includeHeader, long leng1, long leng2 = 0) + { + + } + + /// + /// Writes a property to a BinaryWriter. + /// + /// The BinaryWriter to write from. + /// Whether or not to also write the "header" of the property, which is data considered by the Unreal Engine to be data that is part of the PropertyData base class rather than any particular child class. + /// The length in bytes of the data that was written. + public virtual int Write(AssetBinaryWriter writer, bool includeHeader) + { + return 0; + } + + /// + /// Sets certain fields of the property based off of an array of strings. + /// + /// An array of strings to derive certain fields from. + /// The asset that the property belongs to. + public virtual void FromString(string[] d, UAsset asset) + { + + } + + /// + /// Performs a deep clone of the current PropertyData instance. + /// + /// A deep copy of the current property. + public object Clone() + { + var res = (PropertyData)MemberwiseClone(); + res.Name = (FName)this.Name.Clone(); + if (res.RawValue is ICloneable cloneableValue) res.RawValue = cloneableValue.Clone(); + + HandleCloned(res); + return res; + } + + protected virtual void HandleCloned(PropertyData res) + { + // Child classes can implement this for custom cloning behavior + } + } + + public abstract class PropertyData : PropertyData + { + /// + /// The main value of this property, if such a concept is applicable to the property in question. Properties may contain other values as well, in which case they will be present as other fields in the child class. + /// + [JsonProperty] + public T Value + { + get => GetObject(); + set => SetObject(value); + } + + public PropertyData(FName name) : base(name) + { + + } + + public PropertyData() : base() + { + + } + } +} diff --git a/Translation/UAssetAPI/PropertyTypes/Objects/SetPropertyData.cs b/Translation/UAssetAPI/PropertyTypes/Objects/SetPropertyData.cs new file mode 100644 index 0000000..60decce --- /dev/null +++ b/Translation/UAssetAPI/PropertyTypes/Objects/SetPropertyData.cs @@ -0,0 +1,81 @@ +using UAssetAPI.PropertyTypes.Objects; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.PropertyTypes +{ + /// + /// Describes a set. + /// + public class SetPropertyData : ArrayPropertyData + { + public PropertyData[] ElementsToRemove = null; + + public SetPropertyData(FName name) : base(name) + { + Value = new PropertyData[0]; + ElementsToRemove = new PropertyData[0]; + } + + public SetPropertyData() + { + Value = new PropertyData[0]; + ElementsToRemove = new PropertyData[0]; + } + + private static readonly FString CurrentPropertyType = new FString("SetProperty"); + public override FString PropertyType { get { return CurrentPropertyType; } } + + public override void Read(AssetBinaryReader reader, bool includeHeader, long leng1, long leng2 = 0) + { + this.ShouldSerializeStructsDifferently = false; + + if (includeHeader) + { + ArrayType = reader.ReadFName(); + PropertyGuid = reader.ReadPropertyGuid(); + } + + var removedItemsDummy = new ArrayPropertyData(new FName(reader.Asset, "ElementsToRemove")); + removedItemsDummy.ShouldSerializeStructsDifferently = false; + removedItemsDummy.ArrayType = ArrayType; + removedItemsDummy.Read(reader, false, leng1, leng2); + ElementsToRemove = removedItemsDummy.Value; + + base.Read(reader, false, leng1, leng2); + } + + public override int Write(AssetBinaryWriter writer, bool includeHeader) + { + this.ShouldSerializeStructsDifferently = false; + + if (Value.Length > 0) ArrayType = new FName(writer.Asset, Value[0].PropertyType); + + if (includeHeader) + { + writer.Write(ArrayType); + writer.WritePropertyGuid(PropertyGuid); + } + + var removedItemsDummy = new ArrayPropertyData(new FName(writer.Asset, "ElementsToRemove")); + removedItemsDummy.ShouldSerializeStructsDifferently = false; + removedItemsDummy.ArrayType = ArrayType; + removedItemsDummy.Value = ElementsToRemove; + + int leng1 = removedItemsDummy.Write(writer, false); + return leng1 + base.Write(writer, false); + } + + protected override void HandleCloned(PropertyData res) + { + base.HandleCloned(res); + SetPropertyData cloningProperty = (SetPropertyData)res; + + PropertyData[] newData = new PropertyData[this.ElementsToRemove.Length]; + for (int i = 0; i < this.Value.Length; i++) + { + newData[i] = (PropertyData)this.Value[i].Clone(); + } + cloningProperty.ElementsToRemove = newData; + } + } +} \ No newline at end of file diff --git a/Translation/UAssetAPI/PropertyTypes/Objects/SoftObjectPropertyData.cs b/Translation/UAssetAPI/PropertyTypes/Objects/SoftObjectPropertyData.cs new file mode 100644 index 0000000..44f234a --- /dev/null +++ b/Translation/UAssetAPI/PropertyTypes/Objects/SoftObjectPropertyData.cs @@ -0,0 +1,123 @@ +using Newtonsoft.Json; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.PropertyTypes.Objects +{ + /// + /// Describes a reference variable to another object which may be null, and may become valid or invalid at any point. Synonym for . + /// + public class AssetObjectPropertyData : PropertyData + { + [JsonProperty] + public uint ID = 0; + + public AssetObjectPropertyData(FName name) : base(name) + { + + } + + public AssetObjectPropertyData() + { + + } + + private static readonly FString CurrentPropertyType = new FString("AssetObjectProperty"); + public override FString PropertyType { get { return CurrentPropertyType; } } + + public override void Read(AssetBinaryReader reader, bool includeHeader, long leng1, long leng2 = 0) + { + if (includeHeader) + { + PropertyGuid = reader.ReadPropertyGuid(); + } + + Value = reader.ReadFString(); + } + + public override int Write(AssetBinaryWriter writer, bool includeHeader) + { + if (includeHeader) + { + writer.WritePropertyGuid(PropertyGuid); + } + + return writer.Write(Value); + } + + public override string ToString() + { + return "(" + Value + ", " + ID + ")"; + } + + public override void FromString(string[] d, UAsset asset) + { + asset.AddNameReference(FString.FromString(d[0])); + Value = FString.FromString(d[0]); + } + } + + /// + /// Describes a reference variable to another object which may be null, and may become valid or invalid at any point. Synonym for . + /// + public class SoftObjectPropertyData : PropertyData + { + [JsonProperty] + public uint ID = 0; + + public SoftObjectPropertyData(FName name) : base(name) + { + + } + + public SoftObjectPropertyData() + { + + } + + private static readonly FString CurrentPropertyType = new FString("SoftObjectProperty"); + public override FString PropertyType { get { return CurrentPropertyType; } } + + public override void Read(AssetBinaryReader reader, bool includeHeader, long leng1, long leng2 = 0) + { + if (includeHeader) + { + PropertyGuid = reader.ReadPropertyGuid(); + } + + Value = reader.ReadFName(); + ID = reader.ReadUInt32(); + } + + public override int Write(AssetBinaryWriter writer, bool includeHeader) + { + if (includeHeader) + { + writer.WritePropertyGuid(PropertyGuid); + } + + writer.Write(Value); + writer.Write(ID); + return sizeof(int) * 3; + } + + public override string ToString() + { + return "(" + Value.ToString() + ", " + ID + ")"; + } + + public override void FromString(string[] d, UAsset asset) + { + FName output = FName.FromString(asset, d[0]); + Value = output; + + if (uint.TryParse(d[1], out uint res2)) + { + ID = res2; + } + else + { + ID = 0; + } + } + } +} \ No newline at end of file diff --git a/Translation/UAssetAPI/PropertyTypes/Objects/StrPropertyData.cs b/Translation/UAssetAPI/PropertyTypes/Objects/StrPropertyData.cs new file mode 100644 index 0000000..4d71862 --- /dev/null +++ b/Translation/UAssetAPI/PropertyTypes/Objects/StrPropertyData.cs @@ -0,0 +1,59 @@ +using System.IO; +using System.Text; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.PropertyTypes.Objects +{ + /// + /// Describes an . + /// + public class StrPropertyData : PropertyData + { + public StrPropertyData(FName name) : base(name) + { + + } + + public StrPropertyData() + { + + } + + private static readonly FString CurrentPropertyType = new FString("StrProperty"); + public override FString PropertyType { get { return CurrentPropertyType; } } + + public override void Read(AssetBinaryReader reader, bool includeHeader, long leng1, long leng2 = 0) + { + if (includeHeader) + { + PropertyGuid = reader.ReadPropertyGuid(); + } + + Value = reader.ReadFString(); + } + + public override int Write(AssetBinaryWriter writer, bool includeHeader) + { + if (includeHeader) + { + writer.WritePropertyGuid(PropertyGuid); + } + + int here = (int)writer.BaseStream.Position; + writer.Write(Value); + return (int)writer.BaseStream.Position - here; + } + + public override string ToString() + { + return Value.ToString(); + } + + public override void FromString(string[] d, UAsset asset) + { + var encoding = Encoding.ASCII; + if (d.Length >= 5) encoding = (d[4].Equals("utf-16") ? Encoding.Unicode : Encoding.ASCII); + Value = FString.FromString(d[0], encoding); + } + } +} \ No newline at end of file diff --git a/Translation/UAssetAPI/PropertyTypes/Objects/TextHistoryType.cs b/Translation/UAssetAPI/PropertyTypes/Objects/TextHistoryType.cs new file mode 100644 index 0000000..3e19ce7 --- /dev/null +++ b/Translation/UAssetAPI/PropertyTypes/Objects/TextHistoryType.cs @@ -0,0 +1,20 @@ +namespace UAssetAPI.PropertyTypes.Objects +{ + public enum TextHistoryType + { + None = -1, + Base = 0, + NamedFormat, + OrderedFormat, + ArgumentFormat, + AsNumber, + AsPercent, + AsCurrency, + AsDate, + AsTime, + AsDateTime, + Transform, + StringTableEntry, + TextGenerator + } +} \ No newline at end of file diff --git a/Translation/UAssetAPI/PropertyTypes/Objects/TextPropertyData.cs b/Translation/UAssetAPI/PropertyTypes/Objects/TextPropertyData.cs new file mode 100644 index 0000000..afe74e8 --- /dev/null +++ b/Translation/UAssetAPI/PropertyTypes/Objects/TextPropertyData.cs @@ -0,0 +1,208 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; +using System; +using System.IO; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.PropertyTypes.Objects +{ + [Flags] + public enum ETextFlag + { + Transient = 1 << 0, + CultureInvariant = 1 << 1, + ConvertedProperty = 1 << 2, + Immutable = 1 << 3, + InitializedFromString = 1 << 4 + } + + /// + /// Describes an FText. + /// + public class TextPropertyData : PropertyData + { + /// Flags with various information on what sort of FText this is + [JsonProperty] + public ETextFlag Flags = 0; + /// The HistoryType of this FText. + [JsonProperty] + [JsonConverter(typeof(StringEnumConverter))] + public TextHistoryType HistoryType = TextHistoryType.Base; + /// The string table ID being referenced, if applicable + [JsonProperty] + public FName TableId = null; + /// A namespace to use when parsing texts that use LOCTEXT + [JsonProperty] + public FString Namespace = null; + /// The source string for this FText. In the Unreal Engine, this is also known as SourceString. + [JsonProperty] + public FString CultureInvariantString = null; + + public bool ShouldSerializeTableId() + { + return HistoryType == TextHistoryType.StringTableEntry; + } + + public TextPropertyData(FName name) : base(name) + { + + } + + public TextPropertyData() + { + + } + + private static readonly FString CurrentPropertyType = new FString("TextProperty"); + public override FString PropertyType { get { return CurrentPropertyType; } } + + public override void Read(AssetBinaryReader reader, bool includeHeader, long leng1, long leng2 = 0) + { + if (includeHeader) + { + PropertyGuid = reader.ReadPropertyGuid(); + } + + if (reader.Asset.EngineVersion < UE4Version.VER_UE4_FTEXT_HISTORY) + { + CultureInvariantString = reader.ReadFString(); + if (reader.Asset.EngineVersion >= UE4Version.VER_UE4_ADDED_NAMESPACE_AND_KEY_DATA_TO_FTEXT) + { + Namespace = reader.ReadFString(); + Value = reader.ReadFString(); + } + else + { + Namespace = null; + Value = reader.ReadFString(); + } + } + + Flags = (ETextFlag)reader.ReadUInt32(); + + if (reader.Asset.EngineVersion >= UE4Version.VER_UE4_FTEXT_HISTORY) + { + HistoryType = (TextHistoryType)reader.ReadSByte(); + + switch (HistoryType) + { + case TextHistoryType.None: + Value = null; + if (reader.Asset.GetCustomVersion() >= FEditorObjectVersion.CultureInvariantTextSerializationKeyStability) + { + bool bHasCultureInvariantString = reader.ReadInt32() == 1; + if (bHasCultureInvariantString) + { + CultureInvariantString = reader.ReadFString(); + } + } + break; + case TextHistoryType.Base: + Namespace = reader.ReadFString(); + Value = reader.ReadFString(); + CultureInvariantString = reader.ReadFString(); + break; + case TextHistoryType.StringTableEntry: + TableId = reader.ReadFName(); + Value = reader.ReadFString(); + break; + default: + throw new NotImplementedException("Unimplemented reader for " + HistoryType.ToString()); + } + } + } + + public override int Write(AssetBinaryWriter writer, bool includeHeader) + { + if (includeHeader) + { + writer.WritePropertyGuid(PropertyGuid); + } + + int here = (int)writer.BaseStream.Position; + + if (writer.Asset.EngineVersion < UE4Version.VER_UE4_FTEXT_HISTORY) + { + writer.Write(CultureInvariantString); + if (writer.Asset.EngineVersion >= UE4Version.VER_UE4_ADDED_NAMESPACE_AND_KEY_DATA_TO_FTEXT) + { + writer.Write(Namespace); + writer.Write(Value); + } + else + { + writer.Write(Value); + } + } + + writer.Write((uint)Flags); + + if (writer.Asset.EngineVersion >= UE4Version.VER_UE4_FTEXT_HISTORY) + { + writer.Write((sbyte)HistoryType); + + switch (HistoryType) + { + case TextHistoryType.None: + if (writer.Asset.GetCustomVersion() >= FEditorObjectVersion.CultureInvariantTextSerializationKeyStability) + { + if (CultureInvariantString == null || string.IsNullOrEmpty(CultureInvariantString.Value)) + { + writer.Write(0); + } + else + { + writer.Write(1); + writer.Write(CultureInvariantString); + } + } + break; + case TextHistoryType.Base: + writer.Write(Namespace); + writer.Write(Value); + writer.Write(CultureInvariantString); + break; + case TextHistoryType.StringTableEntry: + writer.Write(TableId); + writer.Write(Value); + break; + default: + throw new NotImplementedException("Unimplemented writer for " + HistoryType.ToString()); + } + } + + return (int)writer.BaseStream.Position - here; + } + + public override string ToString() + { + if (Value == null) return "null"; + + switch (HistoryType) + { + case TextHistoryType.None: + return "None, " + CultureInvariantString; + case TextHistoryType.Base: + return "Base, " + Namespace + ", " + Value + ", " + CultureInvariantString; + case TextHistoryType.StringTableEntry: + return "StringTableEntry, " + TableId + ", " + Value; + default: + throw new NotImplementedException("Unimplemented display for " + HistoryType.ToString()); + } + } + + public override void FromString(string[] d, UAsset asset) + { + throw new NotImplementedException("TextPropertyData.FromString is currently unimplemented"); + } + + protected override void HandleCloned(PropertyData res) + { + TextPropertyData cloningProperty = (TextPropertyData)res; + + cloningProperty.TableId = (FName)TableId.Clone(); + cloningProperty.Namespace = (FString)Namespace.Clone(); + cloningProperty.Namespace = (FString)CultureInvariantString.Clone(); + } + } +} \ No newline at end of file diff --git a/Translation/UAssetAPI/PropertyTypes/Objects/UInt16PropertyData.cs b/Translation/UAssetAPI/PropertyTypes/Objects/UInt16PropertyData.cs new file mode 100644 index 0000000..192b058 --- /dev/null +++ b/Translation/UAssetAPI/PropertyTypes/Objects/UInt16PropertyData.cs @@ -0,0 +1,57 @@ +using System; +using System.IO; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.PropertyTypes.Objects +{ + /// + /// Describes a 16-bit unsigned integer variable (). + /// + public class UInt16PropertyData : PropertyData + { + public UInt16PropertyData(FName name) : base(name) + { + + } + + public UInt16PropertyData() + { + + } + + private static readonly FString CurrentPropertyType = new FString("UInt16Property"); + public override FString PropertyType { get { return CurrentPropertyType; } } + + public override void Read(AssetBinaryReader reader, bool includeHeader, long leng1, long leng2 = 0) + { + if (includeHeader) + { + PropertyGuid = reader.ReadPropertyGuid(); + } + + Value = reader.ReadUInt16(); + } + + public override int Write(AssetBinaryWriter writer, bool includeHeader) + { + if (includeHeader) + { + writer.WritePropertyGuid(PropertyGuid); + } + + writer.Write(Value); + return sizeof(ushort); + } + + public override string ToString() + { + return Convert.ToString(Value); + } + + public override void FromString(string[] d, UAsset asset) + { + Value = 0; + if (ushort.TryParse(d[0], out ushort res)) Value = res; + } + } +} \ No newline at end of file diff --git a/Translation/UAssetAPI/PropertyTypes/Objects/UInt32PropertyData.cs b/Translation/UAssetAPI/PropertyTypes/Objects/UInt32PropertyData.cs new file mode 100644 index 0000000..f44d7cb --- /dev/null +++ b/Translation/UAssetAPI/PropertyTypes/Objects/UInt32PropertyData.cs @@ -0,0 +1,57 @@ +using System; +using System.IO; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.PropertyTypes.Objects +{ + /// + /// Describes a 32-bit unsigned integer variable (). + /// + public class UInt32PropertyData : PropertyData + { + public UInt32PropertyData(FName name) : base(name) + { + + } + + public UInt32PropertyData() + { + + } + + private static readonly FString CurrentPropertyType = new FString("UInt32Property"); + public override FString PropertyType { get { return CurrentPropertyType; } } + + public override void Read(AssetBinaryReader reader, bool includeHeader, long leng1, long leng2 = 0) + { + if (includeHeader) + { + PropertyGuid = reader.ReadPropertyGuid(); + } + + Value = reader.ReadUInt32(); + } + + public override int Write(AssetBinaryWriter writer, bool includeHeader) + { + if (includeHeader) + { + writer.WritePropertyGuid(PropertyGuid); + } + + writer.Write(Value); + return sizeof(uint); + } + + public override string ToString() + { + return Convert.ToString(Value); + } + + public override void FromString(string[] d, UAsset asset) + { + Value = 0; + if (uint.TryParse(d[0], out uint res)) Value = res; + } + } +} \ No newline at end of file diff --git a/Translation/UAssetAPI/PropertyTypes/Objects/UInt64PropertyData.cs b/Translation/UAssetAPI/PropertyTypes/Objects/UInt64PropertyData.cs new file mode 100644 index 0000000..e793b82 --- /dev/null +++ b/Translation/UAssetAPI/PropertyTypes/Objects/UInt64PropertyData.cs @@ -0,0 +1,57 @@ +using System; +using System.IO; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.PropertyTypes.Objects +{ + /// + /// Describes a 64-bit unsigned integer variable (). + /// + public class UInt64PropertyData : PropertyData + { + public UInt64PropertyData(FName name) : base(name) + { + + } + + public UInt64PropertyData() + { + + } + + private static readonly FString CurrentPropertyType = new FString("UInt64Property"); + public override FString PropertyType { get { return CurrentPropertyType; } } + + public override void Read(AssetBinaryReader reader, bool includeHeader, long leng1, long leng2 = 0) + { + if (includeHeader) + { + PropertyGuid = reader.ReadPropertyGuid(); + } + + Value = reader.ReadUInt64(); + } + + public override int Write(AssetBinaryWriter writer, bool includeHeader) + { + if (includeHeader) + { + writer.WritePropertyGuid(PropertyGuid); + } + + writer.Write(Value); + return sizeof(ulong); + } + + public override string ToString() + { + return Convert.ToString(Value); + } + + public override void FromString(string[] d, UAsset asset) + { + Value = 0; + if (ulong.TryParse(d[0], out ulong res)) Value = res; + } + } +} \ No newline at end of file diff --git a/Translation/UAssetAPI/PropertyTypes/Objects/UnknownPropertyData.cs b/Translation/UAssetAPI/PropertyTypes/Objects/UnknownPropertyData.cs new file mode 100644 index 0000000..13a16f1 --- /dev/null +++ b/Translation/UAssetAPI/PropertyTypes/Objects/UnknownPropertyData.cs @@ -0,0 +1,67 @@ +using Newtonsoft.Json; +using System; +using System.IO; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.PropertyTypes.Objects +{ + /// + /// Describes a property which UAssetAPI has no specific serialization for, and is instead represented as an array of bytes as a fallback. + /// + public class UnknownPropertyData : PropertyData + { + [JsonProperty] + public FString SerializingPropertyType = CurrentPropertyType; + + public UnknownPropertyData(FName name) : base(name) + { + + } + + public UnknownPropertyData() + { + + } + + private static readonly FString CurrentPropertyType = new FString("UnknownProperty"); + public override FString PropertyType { get { return CurrentPropertyType; } } + + public void SetSerializingPropertyType(FString newType) + { + SerializingPropertyType = newType; + } + + public override void Read(AssetBinaryReader reader, bool includeHeader, long leng1, long leng2 = 0) + { + if (includeHeader) + { + PropertyGuid = reader.ReadPropertyGuid(); + } + + Value = reader.ReadBytes((int)leng1); + } + + public override int Write(AssetBinaryWriter writer, bool includeHeader) + { + if (includeHeader) + { + writer.WritePropertyGuid(PropertyGuid); + } + + writer.Write(Value); + return Value.Length; + } + + public override string ToString() + { + return Convert.ToString(Value); + } + + protected override void HandleCloned(PropertyData res) + { + UnknownPropertyData cloningProperty = (UnknownPropertyData)res; + + cloningProperty.SerializingPropertyType = (FString)SerializingPropertyType.Clone(); + } + } +} diff --git a/Translation/UAssetAPI/PropertyTypes/Structs/Box2DPropertyData.cs b/Translation/UAssetAPI/PropertyTypes/Structs/Box2DPropertyData.cs new file mode 100644 index 0000000..756ba8a --- /dev/null +++ b/Translation/UAssetAPI/PropertyTypes/Structs/Box2DPropertyData.cs @@ -0,0 +1,87 @@ +using Newtonsoft.Json; +using UAssetAPI.PropertyTypes.Objects; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.PropertyTypes.Structs +{ + public class Box2DPropertyData : PropertyData // Min, Max, IsValid + { + [JsonProperty] + public bool IsValid; + + public Box2DPropertyData(FName name) : base(name) + { + + } + + public Box2DPropertyData() + { + + } + + private static readonly FString CurrentPropertyType = new FString("Box2D"); + public override bool HasCustomStructSerialization { get { return true; } } + public override FString PropertyType { get { return CurrentPropertyType; } } + + public override void Read(AssetBinaryReader reader, bool includeHeader, long leng1, long leng2 = 0) + { + if (includeHeader) + { + PropertyGuid = reader.ReadPropertyGuid(); + } + + Value = new Vector2DPropertyData[2]; + for (int i = 0; i < 2; i++) + { + var next = new Vector2DPropertyData(Name); + next.Read(reader, false, 0); + Value[i] = next; + } + + IsValid = reader.ReadBoolean(); + } + + public override int Write(AssetBinaryWriter writer, bool includeHeader) + { + if (includeHeader) + { + writer.WritePropertyGuid(PropertyGuid); + } + + int totalSize = 0; + for (int i = 0; i < 2; i++) + { + totalSize += Value[i].Write(writer, includeHeader); + } + writer.Write(IsValid); + return totalSize + sizeof(bool); + } + + public override void FromString(string[] d, UAsset asset) + { + IsValid = d[0].Equals("1") || d[0].ToLower().Equals("true"); + } + + public override string ToString() + { + string oup = "("; + for (int i = 0; i < Value.Length; i++) + { + oup += Value[i] + ", "; + } + return oup.Remove(oup.Length - 2) + ")"; + } + + protected override void HandleCloned(PropertyData res) + { + Box2DPropertyData cloningProperty = (Box2DPropertyData)res; + + Vector2DPropertyData[] newData = new Vector2DPropertyData[this.Value.Length]; + for (int i = 0; i < this.Value.Length; i++) + { + newData[i] = (Vector2DPropertyData)this.Value[i].Clone(); + } + cloningProperty.Value = newData; + } + } +} \ No newline at end of file diff --git a/Translation/UAssetAPI/PropertyTypes/Structs/BoxPropertyData.cs b/Translation/UAssetAPI/PropertyTypes/Structs/BoxPropertyData.cs new file mode 100644 index 0000000..eefb4ef --- /dev/null +++ b/Translation/UAssetAPI/PropertyTypes/Structs/BoxPropertyData.cs @@ -0,0 +1,88 @@ +using Newtonsoft.Json; +using System.IO; +using UAssetAPI.PropertyTypes.Objects; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.PropertyTypes.Structs +{ + public class BoxPropertyData : PropertyData // Min, Max, IsValid + { + [JsonProperty] + public bool IsValid; + + public BoxPropertyData(FName name) : base(name) + { + + } + + public BoxPropertyData() + { + + } + + private static readonly FString CurrentPropertyType = new FString("Box"); + public override bool HasCustomStructSerialization { get { return true; } } + public override FString PropertyType { get { return CurrentPropertyType; } } + + public override void Read(AssetBinaryReader reader, bool includeHeader, long leng1, long leng2 = 0) + { + if (includeHeader) + { + PropertyGuid = reader.ReadPropertyGuid(); + } + + Value = new VectorPropertyData[2]; + for (int i = 0; i < 2; i++) + { + var next = new VectorPropertyData(Name); + next.Read(reader, false, 0); + Value[i] = next; + } + + IsValid = reader.ReadBoolean(); + } + + public override int Write(AssetBinaryWriter writer, bool includeHeader) + { + if (includeHeader) + { + writer.WritePropertyGuid(PropertyGuid); + } + + int totalSize = 0; + for (int i = 0; i < 2; i++) + { + totalSize += Value[i].Write(writer, includeHeader); + } + writer.Write(IsValid); + return totalSize + sizeof(bool); + } + + public override void FromString(string[] d, UAsset asset) + { + IsValid = d[0].Equals("1") || d[0].ToLower().Equals("true"); + } + + public override string ToString() + { + string oup = "("; + for (int i = 0; i < Value.Length; i++) + { + oup += Value[i] + ", "; + } + return oup.Remove(oup.Length - 2) + ")"; + } + + protected override void HandleCloned(PropertyData res) + { + BoxPropertyData cloningProperty = (BoxPropertyData)res; + + VectorPropertyData[] newData = new VectorPropertyData[this.Value.Length]; + for (int i = 0; i < this.Value.Length; i++) + { + newData[i] = (VectorPropertyData)this.Value[i].Clone(); + } + cloningProperty.Value = newData; + } + } +} \ No newline at end of file diff --git a/Translation/UAssetAPI/PropertyTypes/Structs/ClothLODDataPropertyData.cs b/Translation/UAssetAPI/PropertyTypes/Structs/ClothLODDataPropertyData.cs new file mode 100644 index 0000000..168be57 --- /dev/null +++ b/Translation/UAssetAPI/PropertyTypes/Structs/ClothLODDataPropertyData.cs @@ -0,0 +1,190 @@ +using System; +using System.IO; +using UAssetAPI.PropertyTypes.Structs; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.PropertyTypes.Structs +{ + /// + /// A structure for holding mesh-to-mesh triangle influences to skin one mesh to another (similar to a wrap deformer) + /// + public class FMeshToMeshVertData + { + /// + /// Barycentric coords and distance along normal for the position of the final vert + /// + public Vector4PropertyData PositionBaryCoordsAndDist; + + /// + /// Barycentric coords and distance along normal for the location of the unit normal endpoint. + /// Actual normal = ResolvedNormalPosition - ResolvedPosition + /// + public Vector4PropertyData NormalBaryCoordsAndDist; + + /// + /// Barycentric coords and distance along normal for the location of the unit Tangent endpoint. + /// Actual normal = ResolvedNormalPosition - ResolvedPosition + /// + public Vector4PropertyData TangentBaryCoordsAndDist; + + /// + /// Contains the 3 indices for verts in the source mesh forming a triangle, the last element + /// is a flag to decide how the skinning works, 0xffff uses no simulation, and just normal + /// skinning, anything else uses the source mesh and the above skin data to get the final position + /// + public ushort[] SourceMeshVertIndices; + + /// + /// For weighted averaging of multiple triangle influences + /// + public float Weight = 0.0f; + + /// + /// Dummy for alignment + /// + public uint Padding; + + public void Read(AssetBinaryReader reader) + { + PositionBaryCoordsAndDist = new Vector4PropertyData(FName.DefineDummy(reader.Asset, "PositionBaryCoordsAndDist")); + PositionBaryCoordsAndDist.Offset = reader.BaseStream.Position; + PositionBaryCoordsAndDist.Read(reader, false, 0); + + NormalBaryCoordsAndDist = new Vector4PropertyData(FName.DefineDummy(reader.Asset, "NormalBaryCoordsAndDist")); + NormalBaryCoordsAndDist.Offset = reader.BaseStream.Position; + NormalBaryCoordsAndDist.Read(reader, false, 0); + + TangentBaryCoordsAndDist = new Vector4PropertyData(FName.DefineDummy(reader.Asset, "TangentBaryCoordsAndDist")); + TangentBaryCoordsAndDist.Offset = reader.BaseStream.Position; + TangentBaryCoordsAndDist.Read(reader, false, 0); + + SourceMeshVertIndices = new ushort[4]; + for (int i = 0; i < 4; i++) + { + SourceMeshVertIndices[i] = reader.ReadUInt16(); + } + + Weight = reader.ReadSingle(); + + Padding = reader.ReadUInt32(); + } + + public int Write(AssetBinaryWriter writer) + { + int res = 0; + res += PositionBaryCoordsAndDist.Write(writer, false); + res += NormalBaryCoordsAndDist.Write(writer, false); + res += TangentBaryCoordsAndDist.Write(writer, false); + + for (int i = 0; i < 4; i++) + { + writer.Write(SourceMeshVertIndices.Length > i ? SourceMeshVertIndices[i] : (ushort)0); res += sizeof(ushort); + } + + writer.Write(Weight); res += sizeof(float); + writer.Write(Padding); res += sizeof(uint); + + return res; + } + + public FMeshToMeshVertData(AssetBinaryReader reader) + { + Read(reader); + } + + public FMeshToMeshVertData(Vector4PropertyData positionBaryCoordsAndDist, Vector4PropertyData normalBaryCoordsAndDist, Vector4PropertyData tangentBaryCoordsAndDist, ushort[] sourceMeshVertIndices, float weight, uint padding) + { + PositionBaryCoordsAndDist = positionBaryCoordsAndDist; + NormalBaryCoordsAndDist = normalBaryCoordsAndDist; + TangentBaryCoordsAndDist = tangentBaryCoordsAndDist; + SourceMeshVertIndices = sourceMeshVertIndices; + Weight = weight; + Padding = padding; + } + + public FMeshToMeshVertData() + { + + } + } + + /// + /// Common Cloth LOD representation for all clothing assets. + /// + public class ClothLODDataPropertyData : StructPropertyData + { + /// + /// Skinning data for transitioning from a higher detail LOD to this one + /// + public FMeshToMeshVertData[] TransitionUpSkinData; + + /// + /// Skinning data for transitioning from a lower detail LOD to this one + /// + public FMeshToMeshVertData[] TransitionDownSkinData; + + public ClothLODDataPropertyData(FName name) : base(name) + { + + } + + public ClothLODDataPropertyData() + { + + } + + private static readonly FString CurrentPropertyType = new FString("ClothLODData"); + public override bool HasCustomStructSerialization { get { return true; } } + public override FString PropertyType { get { return CurrentPropertyType; } } + + public override void Read(AssetBinaryReader reader, bool includeHeader, long leng1, long leng2 = 0) + { + StructType = FName.DefineDummy(reader.Asset, "Generic"); + base.Read(reader, includeHeader, 1, leng2); + + int sizeUpData = reader.ReadInt32(); + TransitionUpSkinData = new FMeshToMeshVertData[sizeUpData]; + for (int i = 0; i < sizeUpData; i++) + { + TransitionUpSkinData[i] = new FMeshToMeshVertData(reader); + } + + int sizeDownData = reader.ReadInt32(); + TransitionDownSkinData = new FMeshToMeshVertData[sizeDownData]; + for (int i = 0; i < sizeDownData; i++) + { + TransitionDownSkinData[i] = new FMeshToMeshVertData(reader); + } + } + + public override int Write(AssetBinaryWriter writer, bool includeHeader) + { + StructType = FName.DefineDummy(writer.Asset, "Generic"); + int res = base.Write(writer, includeHeader); + + writer.Write(TransitionUpSkinData.Length); res += sizeof(int); + for (int i = 0; i < TransitionUpSkinData.Length; i++) + { + res += TransitionUpSkinData[i].Write(writer); + } + + writer.Write(TransitionDownSkinData.Length); res += sizeof(int); + for (int i = 0; i < TransitionDownSkinData.Length; i++) + { + res += TransitionDownSkinData[i].Write(writer); + } + + return res; + } + + public override string ToString() + { + return base.ToString(); + } + + public override void FromString(string[] d, UAsset asset) + { + base.FromString(d, asset); + } + } +} \ No newline at end of file diff --git a/Translation/UAssetAPI/PropertyTypes/Structs/ColorPropertyData.cs b/Translation/UAssetAPI/PropertyTypes/Structs/ColorPropertyData.cs new file mode 100644 index 0000000..4625d61 --- /dev/null +++ b/Translation/UAssetAPI/PropertyTypes/Structs/ColorPropertyData.cs @@ -0,0 +1,68 @@ +using System.Drawing; +using System.IO; +using UAssetAPI.PropertyTypes.Objects; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.PropertyTypes.Structs +{ + /// + /// Describes a color with 8 bits of precision per channel. + /// + public class ColorPropertyData : PropertyData // R, G, B, A + { + public ColorPropertyData(FName name) : base(name) + { + + } + + public ColorPropertyData() + { + + } + + private static readonly FString CurrentPropertyType = new FString("Color"); + public override bool HasCustomStructSerialization { get { return true; } } + public override FString PropertyType { get { return CurrentPropertyType; } } + + public override void Read(AssetBinaryReader reader, bool includeHeader, long leng1, long leng2 = 0) + { + if (includeHeader) + { + PropertyGuid = reader.ReadPropertyGuid(); + } + + Value = Color.FromArgb(reader.ReadInt32()); + } + + public override int Write(AssetBinaryWriter writer, bool includeHeader) + { + if (includeHeader) + { + writer.WritePropertyGuid(PropertyGuid); + } + + writer.Write(Value.ToArgb()); + return sizeof(int); + } + + public override string ToString() + { + return Value.ToString(); + } + + public override void FromString(string[] d, UAsset asset) + { + if (!int.TryParse(d[0], out int colorR)) return; + if (!int.TryParse(d[1], out int colorG)) return; + if (!int.TryParse(d[2], out int colorB)) return; + if (!int.TryParse(d[3], out int colorA)) return; + Value = Color.FromArgb(colorA, colorR, colorG, colorB); + } + + protected override void HandleCloned(PropertyData res) + { + ColorPropertyData cloningProperty = (ColorPropertyData)res; + cloningProperty.Value = Color.FromArgb(this.Value.ToArgb()); + } + } +} \ No newline at end of file diff --git a/Translation/UAssetAPI/PropertyTypes/Structs/DateTimePropertyData.cs b/Translation/UAssetAPI/PropertyTypes/Structs/DateTimePropertyData.cs new file mode 100644 index 0000000..5a5b60e --- /dev/null +++ b/Translation/UAssetAPI/PropertyTypes/Structs/DateTimePropertyData.cs @@ -0,0 +1,72 @@ +using System; +using System.IO; +using UAssetAPI.PropertyTypes.Objects; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.PropertyTypes.Structs +{ + /// + /// Implements a date and time. + /// + /// Values of this type represent dates and times between Midnight 00:00:00, January 1, 0001 and + /// Midnight 23:59:59.9999999, December 31, 9999 in the Gregorian calendar. Internally, the time + /// values are stored in ticks of 0.1 microseconds (= 100 nanoseconds) since January 1, 0001. + /// + /// The companion class () is provided for + /// enabling date and time based arithmetic, such as calculating the difference between two dates + /// or adding a certain amount of time to a given date. + /// + public class DateTimePropertyData : PropertyData + { + public DateTimePropertyData(FName name) : base(name) + { + + } + + public DateTimePropertyData() + { + + } + + private static readonly FString CurrentPropertyType = new FString("DateTime"); + public override bool HasCustomStructSerialization { get { return true; } } + public override FString PropertyType { get { return CurrentPropertyType; } } + + public override void Read(AssetBinaryReader reader, bool includeHeader, long leng1, long leng2 = 0) + { + if (includeHeader) + { + PropertyGuid = reader.ReadPropertyGuid(); + } + + Value = new DateTime(reader.ReadInt64()); // number of ticks since January 1, 0001 + } + + public override int Write(AssetBinaryWriter writer, bool includeHeader) + { + if (includeHeader) + { + writer.WritePropertyGuid(PropertyGuid); + } + + writer.Write(Value.Ticks); + return sizeof(long); + } + + public override void FromString(string[] d, UAsset asset) + { + Value = DateTime.Parse(d[0]); + } + + public override string ToString() + { + return Value.ToString(); + } + + protected override void HandleCloned(PropertyData res) + { + DateTimePropertyData cloningProperty = (DateTimePropertyData)res; + cloningProperty.Value = new DateTime(cloningProperty.Value.Ticks); + } + } +} \ No newline at end of file diff --git a/Translation/UAssetAPI/PropertyTypes/Structs/GameplayTagContainerPropertyData.cs b/Translation/UAssetAPI/PropertyTypes/Structs/GameplayTagContainerPropertyData.cs new file mode 100644 index 0000000..eabaee6 --- /dev/null +++ b/Translation/UAssetAPI/PropertyTypes/Structs/GameplayTagContainerPropertyData.cs @@ -0,0 +1,78 @@ +using System; +using System.IO; +using UAssetAPI.PropertyTypes.Objects; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.PropertyTypes.Structs +{ + public class GameplayTagContainerPropertyData : PropertyData + { + public GameplayTagContainerPropertyData(FName name) : base(name) + { + Value = new FName[0]; + } + + public GameplayTagContainerPropertyData() + { + Value = new FName[0]; + } + + private static readonly FString CurrentPropertyType = new FString("GameplayTagContainer"); + public override bool HasCustomStructSerialization { get { return true; } } + public override FString PropertyType { get { return CurrentPropertyType; } } + + public override void Read(AssetBinaryReader reader, bool includeHeader, long leng1, long leng2 = 0) + { + if (includeHeader) + { + PropertyGuid = reader.ReadPropertyGuid(); + } + + int numEntries = reader.ReadInt32(); + Value = new FName[numEntries]; + for (int i = 0; i < numEntries; i++) + { + Value[i] = reader.ReadFName(); + } + } + + public override int Write(AssetBinaryWriter writer, bool includeHeader) + { + if (includeHeader) + { + writer.WritePropertyGuid(PropertyGuid); + } + + writer.Write(Value.Length); + int totalSize = sizeof(int); + for (int i = 0; i < Value.Length; i++) + { + writer.Write(Value[i]); + totalSize += sizeof(int) * 2; + } + return totalSize; + } + + public override string ToString() + { + string oup = "("; + for (int i = 0; i < Value.Length; i++) + { + oup += Convert.ToString(Value[i]) + ", "; + } + return oup.Remove(oup.Length - 2) + ")"; + } + + protected override void HandleCloned(PropertyData res) + { + GameplayTagContainerPropertyData cloningProperty = (GameplayTagContainerPropertyData)res; + + FName[] newData = new FName[this.Value.Length]; + for (int i = 0; i < this.Value.Length; i++) + { + newData[i] = (FName)this.Value[i].Clone(); + } + cloningProperty.Value = newData; + } + } +} \ No newline at end of file diff --git a/Translation/UAssetAPI/PropertyTypes/Structs/GuidPropertyData.cs b/Translation/UAssetAPI/PropertyTypes/Structs/GuidPropertyData.cs new file mode 100644 index 0000000..f5c4f7c --- /dev/null +++ b/Translation/UAssetAPI/PropertyTypes/Structs/GuidPropertyData.cs @@ -0,0 +1,65 @@ +using System; +using System.IO; +using UAssetAPI.PropertyTypes.Objects; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.PropertyTypes.Structs +{ + /// + /// Describes a 128-bit . + /// + public class GuidPropertyData : PropertyData + { + public GuidPropertyData(FName name) : base(name) + { + + } + + public GuidPropertyData() + { + + } + + private static readonly FString CurrentPropertyType = new FString("Guid"); + public override bool HasCustomStructSerialization { get { return true; } } + public override FString PropertyType { get { return CurrentPropertyType; } } + + public override void Read(AssetBinaryReader reader, bool includeHeader, long leng1, long leng2 = 0) + { + if (includeHeader) + { + PropertyGuid = reader.ReadPropertyGuid(); + } + + Value = new Guid(reader.ReadBytes(16)); + } + + public override int Write(AssetBinaryWriter writer, bool includeHeader) + { + if (includeHeader) + { + writer.WritePropertyGuid(PropertyGuid); + } + + writer.Write(Value.ToByteArray()); + return 16; + } + + public override string ToString() + { + return Value.ConvertToString(); + } + + public override void FromString(string[] d, UAsset asset) + { + Value = d[0].ConvertToGUID(); + } + + protected override void HandleCloned(PropertyData res) + { + GuidPropertyData cloningProperty = (GuidPropertyData)res; + + cloningProperty.Value = new Guid(Value.ToByteArray()); + } + } +} \ No newline at end of file diff --git a/Translation/UAssetAPI/PropertyTypes/Structs/IntPointPropertyData.cs b/Translation/UAssetAPI/PropertyTypes/Structs/IntPointPropertyData.cs new file mode 100644 index 0000000..5fb0c64 --- /dev/null +++ b/Translation/UAssetAPI/PropertyTypes/Structs/IntPointPropertyData.cs @@ -0,0 +1,69 @@ +using System; +using System.IO; +using UAssetAPI.PropertyTypes.Objects; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.PropertyTypes.Structs +{ + public class IntPointPropertyData : PropertyData // X, Y + { + public IntPointPropertyData(FName name) : base(name) + { + + } + + public IntPointPropertyData() + { + + } + + private static readonly FString CurrentPropertyType = new FString("IntPoint"); + public override bool HasCustomStructSerialization { get { return true; } } + public override FString PropertyType { get { return CurrentPropertyType; } } + + public override void Read(AssetBinaryReader reader, bool includeHeader, long leng1, long leng2 = 0) + { + if (includeHeader) + { + PropertyGuid = reader.ReadPropertyGuid(); + } + + Value = new int[2]; + for (int i = 0; i < 2; i++) + { + Value[i] = reader.ReadInt32(); + } + } + + public override int Write(AssetBinaryWriter writer, bool includeHeader) + { + if (includeHeader) + { + writer.WritePropertyGuid(PropertyGuid); + } + + for (int i = 0; i < 2; i++) + { + writer.Write(Value[i]); + } + return sizeof(int) * 2; + } + + public override void FromString(string[] d, UAsset asset) + { + Value = new int[2]; + if (int.TryParse(d[0], out int res1)) Value[0] = res1; + if (int.TryParse(d[1], out int res2)) Value[1] = res2; + } + + public override string ToString() + { + string oup = "("; + for (int i = 0; i < Value.Length; i++) + { + oup += Convert.ToString(Value[i]) + ", "; + } + return oup.Remove(oup.Length - 2) + ")"; + } + } +} \ No newline at end of file diff --git a/Translation/UAssetAPI/PropertyTypes/Structs/LinearColorPropertyData.cs b/Translation/UAssetAPI/PropertyTypes/Structs/LinearColorPropertyData.cs new file mode 100644 index 0000000..605c10a --- /dev/null +++ b/Translation/UAssetAPI/PropertyTypes/Structs/LinearColorPropertyData.cs @@ -0,0 +1,120 @@ +using Newtonsoft.Json; +using System; +using System.Drawing; +using System.IO; +using UAssetAPI.PropertyTypes.Objects; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.PropertyTypes.Structs +{ + public static class LinearHelpers + { + public static Color Convert(LinearColor color) + { + float FloatR = UAPUtils.Clamp(color.R, 0.0f, 1.0f); + float FloatG = UAPUtils.Clamp(color.G, 0.0f, 1.0f); + float FloatB = UAPUtils.Clamp(color.B, 0.0f, 1.0f); + float FloatA = UAPUtils.Clamp(color.A, 0.0f, 1.0f); + + FloatR = (float)(FloatR <= 0.0031308f ? FloatR * 12.92f : Math.Pow(FloatR, 1.0f / 2.4f) * 1.055f - 0.055f); + FloatG = (float)(FloatG <= 0.0031308f ? FloatG * 12.92f : Math.Pow(FloatG, 1.0f / 2.4f) * 1.055f - 0.055f); + FloatB = (float)(FloatB <= 0.0031308f ? FloatB * 12.92f : Math.Pow(FloatB, 1.0f / 2.4f) * 1.055f - 0.055f); + + return Color.FromArgb((byte)Math.Floor(FloatA * 255.999f), (byte)Math.Floor(FloatR * 255.999f), (byte)Math.Floor(FloatG * 255.999f), (byte)Math.Floor(FloatB * 255.999f)); + } + } + + /// + /// A linear, 32-bit/component floating point RGBA color. + /// + public class LinearColor : ICloneable + { + [JsonProperty] + public float R; + [JsonProperty] + public float G; + [JsonProperty] + public float B; + [JsonProperty] + public float A; + + public LinearColor() + { + + } + + public LinearColor(float R, float G, float B, float A) + { + this.R = R; + this.G = G; + this.B = B; + this.A = A; + } + + public object Clone() + { + return new LinearColor(this.R, this.G, this.B, this.A); + } + } + + public class LinearColorPropertyData : PropertyData // R, G, B, A + { + public LinearColorPropertyData(FName name) : base(name) + { + + } + + public LinearColorPropertyData() + { + + } + + private static readonly FString CurrentPropertyType = new FString("LinearColor"); + public override bool HasCustomStructSerialization { get { return true; } } + public override FString PropertyType { get { return CurrentPropertyType; } } + + public override void Read(AssetBinaryReader reader, bool includeHeader, long leng1, long leng2 = 0) + { + if (includeHeader) + { + PropertyGuid = reader.ReadPropertyGuid(); + } + + Value = new LinearColor + { + R = reader.ReadSingle(), + G = reader.ReadSingle(), + B = reader.ReadSingle(), + A = reader.ReadSingle() + }; + } + + public override int Write(AssetBinaryWriter writer, bool includeHeader) + { + if (includeHeader) + { + writer.WritePropertyGuid(PropertyGuid); + } + + writer.Write(Value.R); + writer.Write(Value.G); + writer.Write(Value.B); + writer.Write(Value.A); + return sizeof(float) * 4; + } + + public override string ToString() + { + return Value.ToString(); + } + + public override void FromString(string[] d, UAsset asset) + { + if (!float.TryParse(d[0], out float colorR)) return; + if (!float.TryParse(d[1], out float colorG)) return; + if (!float.TryParse(d[2], out float colorB)) return; + if (!float.TryParse(d[3], out float colorA)) return; + Value = new LinearColor(colorR, colorG, colorB, colorA); + } + } +} \ No newline at end of file diff --git a/Translation/UAssetAPI/PropertyTypes/Structs/MaterialInputProperties.cs b/Translation/UAssetAPI/PropertyTypes/Structs/MaterialInputProperties.cs new file mode 100644 index 0000000..cfe8ae7 --- /dev/null +++ b/Translation/UAssetAPI/PropertyTypes/Structs/MaterialInputProperties.cs @@ -0,0 +1,355 @@ +using Newtonsoft.Json; +using UAssetAPI.PropertyTypes.Objects; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.PropertyTypes.Structs +{ + public abstract class MaterialInputPropertyData : PropertyData + { + [JsonProperty] + public int OutputIndex; + [JsonProperty] + public FString InputName; + [JsonProperty] + public FName ExpressionName; + + public MaterialInputPropertyData() + { + + } + + public MaterialInputPropertyData(FName name) : base(name) + { + + } + + protected void ReadExpressionInput(AssetBinaryReader reader, bool includeHeader, long leng) + { + if (reader.Asset.GetCustomVersion() >= FCoreObjectVersion.MaterialInputNativeSerialize) + { + OutputIndex = reader.ReadInt32(); + if (reader.Asset.GetCustomVersion() >= FFrameworkObjectVersion.PinsStoreFName) + { + InputName = reader.ReadFName().Value; + } + else + { + InputName = reader.ReadFString(); + } + reader.ReadBytes(20); // editor only data placeholder + ExpressionName = reader.ReadFName(); + } + } + + protected int WriteExpressionInput(AssetBinaryWriter writer, bool includeHeader) + { + int totalSize = 0; + if (writer.Asset.GetCustomVersion() >= FCoreObjectVersion.MaterialInputNativeSerialize) + { + writer.Write(OutputIndex); totalSize += sizeof(int); + if (writer.Asset.GetCustomVersion() >= FFrameworkObjectVersion.PinsStoreFName) + { + writer.Write(new FName(writer.Asset, InputName)); totalSize += sizeof(int) * 2; + } + else + { + totalSize += writer.Write(InputName); + } + writer.Write(new byte[20]); totalSize += 20; + writer.Write(ExpressionName); totalSize += sizeof(int) * 2; + } + return totalSize; + } + + protected override void HandleCloned(PropertyData res) + { + MaterialInputPropertyData cloningProperty = (MaterialInputPropertyData)res; + cloningProperty.InputName = (FString)this.InputName.Clone(); + cloningProperty.ExpressionName = (FName)this.ExpressionName.Clone(); + } + } + + public class ExpressionInputPropertyData : MaterialInputPropertyData + { + public ExpressionInputPropertyData(FName name) : base(name) + { + + } + + public ExpressionInputPropertyData() + { + + } + + private static readonly FString CurrentPropertyType = new FString("ExpressionInput"); + public override bool HasCustomStructSerialization { get { return true; } } + public override FString PropertyType { get { return CurrentPropertyType; } } + + public override void Read(AssetBinaryReader reader, bool includeHeader, long leng1, long leng2 = 0) + { + if (includeHeader) + { + PropertyGuid = reader.ReadPropertyGuid(); + } + + ReadExpressionInput(reader, false, 0); + } + + public override int Write(AssetBinaryWriter writer, bool includeHeader) + { + if (includeHeader) + { + writer.WritePropertyGuid(PropertyGuid); + } + + return WriteExpressionInput(writer, false); + } + } + + public class MaterialAttributesInputPropertyData : MaterialInputPropertyData + { + public MaterialAttributesInputPropertyData(FName name) : base(name) + { + + } + + public MaterialAttributesInputPropertyData() + { + + } + + private static readonly FString CurrentPropertyType = new FString("MaterialAttributesInput"); + public override bool HasCustomStructSerialization { get { return true; } } + public override FString PropertyType { get { return CurrentPropertyType; } } + + public override void Read(AssetBinaryReader reader, bool includeHeader, long leng1, long leng2 = 0) + { + if (includeHeader) + { + PropertyGuid = reader.ReadPropertyGuid(); + } + + ReadExpressionInput(reader, false, 0); + } + + public override int Write(AssetBinaryWriter writer, bool includeHeader) + { + if (includeHeader) + { + writer.WritePropertyGuid(PropertyGuid); + } + + return WriteExpressionInput(writer, false); + } + } + + public class ColorMaterialInputPropertyData : MaterialInputPropertyData + { + public ColorMaterialInputPropertyData(FName name) : base(name) + { + + } + + public ColorMaterialInputPropertyData() + { + + } + + private static readonly FString CurrentPropertyType = new FString("ColorMaterialInput"); + public override bool HasCustomStructSerialization { get { return true; } } + public override FString PropertyType { get { return CurrentPropertyType; } } + + public override void Read(AssetBinaryReader reader, bool includeHeader, long leng1, long leng2 = 0) + { + if (includeHeader) + { + PropertyGuid = reader.ReadPropertyGuid(); + } + + ReadExpressionInput(reader, false, 0); + reader.ReadInt32(); // bUseConstantValue; always false + Value = new ColorPropertyData(Name); + Value.Read(reader, false, 0); + } + + public override int Write(AssetBinaryWriter writer, bool includeHeader) + { + if (includeHeader) + { + writer.WritePropertyGuid(PropertyGuid); + } + + int expLength = WriteExpressionInput(writer, false); + writer.Write((int)0); + return expLength + Value.Write(writer, false) + sizeof(int); + } + } + + public class ScalarMaterialInputPropertyData : MaterialInputPropertyData + { + public ScalarMaterialInputPropertyData(FName name) : base(name) + { + + } + + public ScalarMaterialInputPropertyData() + { + + } + + private static readonly FString CurrentPropertyType = new FString("ScalarMaterialInput"); + public override bool HasCustomStructSerialization { get { return true; } } + public override FString PropertyType { get { return CurrentPropertyType; } } + + public override void Read(AssetBinaryReader reader, bool includeHeader, long leng1, long leng2 = 0) + { + if (includeHeader) + { + PropertyGuid = reader.ReadPropertyGuid(); + } + + ReadExpressionInput(reader, false, 0); + reader.ReadInt32(); // bUseConstantValue; always false + Value = reader.ReadSingle(); + } + + public override int Write(AssetBinaryWriter writer, bool includeHeader) + { + if (includeHeader) + { + writer.WritePropertyGuid(PropertyGuid); + } + + int expLength = WriteExpressionInput(writer, false); + writer.Write((int)0); + writer.Write(Value); + return expLength + sizeof(float) + sizeof(int); + } + } + + public class ShadingModelMaterialInputPropertyData : MaterialInputPropertyData + { + public ShadingModelMaterialInputPropertyData(FName name) : base(name) + { + + } + + public ShadingModelMaterialInputPropertyData() + { + + } + + private static readonly FString CurrentPropertyType = new FString("ShadingModelMaterialInput"); + public override bool HasCustomStructSerialization { get { return true; } } + public override FString PropertyType { get { return CurrentPropertyType; } } + + public override void Read(AssetBinaryReader reader, bool includeHeader, long leng1, long leng2 = 0) + { + if (includeHeader) + { + PropertyGuid = reader.ReadPropertyGuid(); + } + + ReadExpressionInput(reader, false, 0); + reader.ReadInt32(); // bUseConstantValue; always false + Value = reader.ReadUInt32(); + } + + public override int Write(AssetBinaryWriter writer, bool includeHeader) + { + if (includeHeader) + { + writer.WritePropertyGuid(PropertyGuid); + } + + int expLength = WriteExpressionInput(writer, false); + writer.Write((int)0); + writer.Write(Value); + return expLength + sizeof(uint) + sizeof(int); + } + } + + public class VectorMaterialInputPropertyData : MaterialInputPropertyData + { + public VectorMaterialInputPropertyData(FName name) : base(name) + { + + } + + public VectorMaterialInputPropertyData() + { + + } + + private static readonly FString CurrentPropertyType = new FString("VectorMaterialInput"); + public override bool HasCustomStructSerialization { get { return true; } } + public override FString PropertyType { get { return CurrentPropertyType; } } + + public override void Read(AssetBinaryReader reader, bool includeHeader, long leng1, long leng2 = 0) + { + if (includeHeader) + { + PropertyGuid = reader.ReadPropertyGuid(); + } + + ReadExpressionInput(reader, false, 0); + reader.ReadInt32(); // bUseConstantValue; always false + Value = new VectorPropertyData(Name); + Value.Read(reader, false, 0); + } + + public override int Write(AssetBinaryWriter writer, bool includeHeader) + { + if (includeHeader) + { + writer.WritePropertyGuid(PropertyGuid); + } + + int expLength = WriteExpressionInput(writer, false); + writer.Write((int)0); + return expLength + Value.Write(writer, false) + sizeof(int); + } + } + + public class Vector2MaterialInputPropertyData : MaterialInputPropertyData + { + public Vector2MaterialInputPropertyData(FName name) : base(name) + { + + } + + public Vector2MaterialInputPropertyData() + { + + } + + private static readonly FString CurrentPropertyType = new FString("Vector2MaterialInput"); + public override bool HasCustomStructSerialization { get { return true; } } + public override FString PropertyType { get { return CurrentPropertyType; } } + + public override void Read(AssetBinaryReader reader, bool includeHeader, long leng1, long leng2 = 0) + { + if (includeHeader) + { + PropertyGuid = reader.ReadPropertyGuid(); + } + + ReadExpressionInput(reader, false, 0); + reader.ReadInt32(); // bUseConstantValue; always false + Value = new Vector2DPropertyData(Name); + Value.Read(reader, false, 0); + } + + public override int Write(AssetBinaryWriter writer, bool includeHeader) + { + if (includeHeader) + { + writer.WritePropertyGuid(PropertyGuid); + } + + int expLength = WriteExpressionInput(writer, false); + writer.Write((int)0); + return expLength + Value.Write(writer, false) + sizeof(int); + } + } +} diff --git a/Translation/UAssetAPI/PropertyTypes/Structs/Movies/MovieSceneSegmentIdentifierPropertyData.cs b/Translation/UAssetAPI/PropertyTypes/Structs/Movies/MovieSceneSegmentIdentifierPropertyData.cs new file mode 100644 index 0000000..963da01 --- /dev/null +++ b/Translation/UAssetAPI/PropertyTypes/Structs/Movies/MovieSceneSegmentIdentifierPropertyData.cs @@ -0,0 +1,58 @@ +using System; +using System.IO; +using UAssetAPI.PropertyTypes.Objects; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.PropertyTypes.Structs.Movies +{ + /// + /// A unique identifier for a segment within a FMovieSceneEvaluationTrackSegments container (IdentifierIndex) + /// + public class MovieSceneSegmentIdentifierPropertyData : PropertyData + { + public MovieSceneSegmentIdentifierPropertyData(FName name) : base(name) + { + + } + + public MovieSceneSegmentIdentifierPropertyData() + { + + } + + private static readonly FString CurrentPropertyType = new FString("MovieSceneSegmentIdentifier"); + public override bool HasCustomStructSerialization { get { return true; } } + public override FString PropertyType { get { return CurrentPropertyType; } } + + public override void Read(AssetBinaryReader reader, bool includeHeader, long leng1, long leng2 = 0) + { + if (includeHeader) + { + PropertyGuid = reader.ReadPropertyGuid(); + } + + Value = reader.ReadInt32(); + } + + public override int Write(AssetBinaryWriter writer, bool includeHeader) + { + if (includeHeader) + { + writer.WritePropertyGuid(PropertyGuid); + } + + writer.Write(Value); + return sizeof(int); + } + + public override void FromString(string[] d, UAsset asset) + { + Value = int.Parse(d[0]); + } + + public override string ToString() + { + return Value.ToString(); + } + } +} \ No newline at end of file diff --git a/Translation/UAssetAPI/PropertyTypes/Structs/Movies/MovieSceneSegmentPropertyData.cs b/Translation/UAssetAPI/PropertyTypes/Structs/Movies/MovieSceneSegmentPropertyData.cs new file mode 100644 index 0000000..509a529 --- /dev/null +++ b/Translation/UAssetAPI/PropertyTypes/Structs/Movies/MovieSceneSegmentPropertyData.cs @@ -0,0 +1,129 @@ +using System; +using System.IO; +using UAssetAPI.PropertyTypes.Objects; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.PropertyTypes.Structs.Movies +{ + /// + /// Information about a single segment of an evaluation track + /// + public class MovieSceneSegmentPropertyData : PropertyData + { + /// + /// The segment's range + /// + public Range Range; + + public MovieSceneSegmentIdentifierPropertyData ID; + + /// + /// Whether this segment has been generated yet or not + /// + public bool bAllowEmpty; + + /// + /// Array of implementations that reside at the segment's range + /// + public StructPropertyData[] Impls; + + public MovieSceneSegmentPropertyData(FName name) : base(name) + { + + } + + public MovieSceneSegmentPropertyData() + { + + } + + private static readonly FString CurrentPropertyType = new FString("MovieSceneSegment"); + public override bool HasCustomStructSerialization { get { return true; } } + public override FString PropertyType { get { return CurrentPropertyType; } } + + // Note: FFrameNumber is serialized as a single int32 + // TODO: doesn't seem to really match how these are actually serialized, double-check serialization + public override void Read(AssetBinaryReader reader, bool includeHeader, long leng1, long leng2 = 0) + { + if (includeHeader) + { + PropertyGuid = reader.ReadPropertyGuid(); + } + + if (reader.Asset.GetCustomVersion() < FSequencerObjectVersion.FloatToIntConversion) + { + Range = new Range(reader.ReadSingle(), reader.ReadSingle()); + } + else + { + Range = new Range(reader.ReadInt32(), reader.ReadInt32()); + } + + if (reader.Asset.GetCustomVersion() >= FSequencerObjectVersion.EvaluationTree) + { + ID = new MovieSceneSegmentIdentifierPropertyData(); + ID.Offset = reader.BaseStream.Position; + ID.Read(reader, false, 0); + + bAllowEmpty = reader.ReadBoolean(); + } + + int numStructs = reader.ReadInt32(); + Impls = new StructPropertyData[numStructs]; + for (int i = 0; i < numStructs; i++) + { + Impls[i] = new StructPropertyData(FName.DefineDummy(reader.Asset, "Impls")); + Impls[i].Offset = reader.BaseStream.Position; + Impls[i].StructType = FName.DefineDummy(reader.Asset, "SectionEvaluationData"); + Impls[i].Read(reader, false, 1); + } + } + + public override int Write(AssetBinaryWriter writer, bool includeHeader) + { + if (includeHeader) + { + writer.WritePropertyGuid(PropertyGuid); + } + + int res = 0; + if (writer.Asset.GetCustomVersion() < FSequencerObjectVersion.FloatToIntConversion) + { + writer.Write((float)Range.LowerBound); + writer.Write((float)Range.UpperBound); + res += sizeof(float) * 2; + } + else + { + writer.Write((int)Range.LowerBound); + writer.Write((int)Range.UpperBound); + res += sizeof(int) * 2; + } + + if (writer.Asset.GetCustomVersion() >= FSequencerObjectVersion.EvaluationTree) + { + ID.Write(writer, false); + + writer.Write(bAllowEmpty); + } + + writer.Write(Impls.Length); + for (int i = 0; i < Impls.Length; i++) + { + Impls[i].Write(writer, false); + } + + return res; + } + + public override void FromString(string[] d, UAsset asset) + { + Range = new Range(float.Parse(d[0]), float.Parse(d[1])); + ID = new MovieSceneSegmentIdentifierPropertyData() + { + Value = int.Parse(d[2]) + }; + bAllowEmpty = d[3].ToLowerInvariant() == "true" || d[3] == "1"; + } + } +} \ No newline at end of file diff --git a/Translation/UAssetAPI/PropertyTypes/Structs/Movies/MovieSceneTrackIdentifierPropertyData.cs b/Translation/UAssetAPI/PropertyTypes/Structs/Movies/MovieSceneTrackIdentifierPropertyData.cs new file mode 100644 index 0000000..f6648bd --- /dev/null +++ b/Translation/UAssetAPI/PropertyTypes/Structs/Movies/MovieSceneTrackIdentifierPropertyData.cs @@ -0,0 +1,55 @@ +using System; +using System.IO; +using UAssetAPI.PropertyTypes.Objects; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.PropertyTypes.Structs.Movies +{ + public class MovieSceneTrackIdentifierPropertyData : PropertyData + { + public MovieSceneTrackIdentifierPropertyData(FName name) : base(name) + { + + } + + public MovieSceneTrackIdentifierPropertyData() + { + + } + + private static readonly FString CurrentPropertyType = new FString("MovieSceneTrackIdentifier"); + public override bool HasCustomStructSerialization { get { return true; } } + public override FString PropertyType { get { return CurrentPropertyType; } } + + public override void Read(AssetBinaryReader reader, bool includeHeader, long leng1, long leng2 = 0) + { + if (includeHeader) + { + PropertyGuid = reader.ReadPropertyGuid(); + } + + Value = reader.ReadUInt32(); + } + + public override int Write(AssetBinaryWriter writer, bool includeHeader) + { + if (includeHeader) + { + writer.WritePropertyGuid(PropertyGuid); + } + + writer.Write(Value); + return sizeof(uint); + } + + public override void FromString(string[] d, UAsset asset) + { + Value = uint.Parse(d[0]); + } + + public override string ToString() + { + return Value.ToString(); + } + } +} \ No newline at end of file diff --git a/Translation/UAssetAPI/PropertyTypes/Structs/Movies/Range.cs b/Translation/UAssetAPI/PropertyTypes/Structs/Movies/Range.cs new file mode 100644 index 0000000..3d830d1 --- /dev/null +++ b/Translation/UAssetAPI/PropertyTypes/Structs/Movies/Range.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.PropertyTypes.Structs.Movies +{ + /// + /// Represents a range that has start and end indexes. + /// + public class Range + { + /// + /// Holds the range's lower bound. + /// + public T LowerBound; + + /// + /// Holds the range's upper bound. + /// + public T UpperBound; + + public Range(T lowerBound, T upperBound) + { + LowerBound = lowerBound; + UpperBound = upperBound; + } + + public Range() + { + + } + } +} diff --git a/Translation/UAssetAPI/PropertyTypes/Structs/PerPlatformBoolPropertyData.cs b/Translation/UAssetAPI/PropertyTypes/Structs/PerPlatformBoolPropertyData.cs new file mode 100644 index 0000000..c9d2fe7 --- /dev/null +++ b/Translation/UAssetAPI/PropertyTypes/Structs/PerPlatformBoolPropertyData.cs @@ -0,0 +1,78 @@ +using System; +using System.Collections.Generic; +using System.IO; +using UAssetAPI.PropertyTypes.Objects; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.PropertyTypes.Structs +{ + /// + /// () property with per-platform overrides. + /// + public class PerPlatformBoolPropertyData : PropertyData + { + public PerPlatformBoolPropertyData(FName name) : base(name) + { + + } + + public PerPlatformBoolPropertyData() + { + + } + + private static readonly FString CurrentPropertyType = new FString("PerPlatformBool"); + public override bool HasCustomStructSerialization { get { return true; } } + public override FString PropertyType { get { return CurrentPropertyType; } } + + public override void Read(AssetBinaryReader reader, bool includeHeader, long leng1, long leng2 = 0) + { + if (includeHeader) + { + PropertyGuid = reader.ReadPropertyGuid(); + } + + int numEntries = reader.ReadInt32(); + Value = new bool[numEntries]; + for (int i = 0; i < numEntries; i++) + { + Value[i] = reader.ReadBoolean(); + } + } + + public override int Write(AssetBinaryWriter writer, bool includeHeader) + { + if (includeHeader) + { + writer.WritePropertyGuid(PropertyGuid); + } + + writer.Write(Value.Length); + for (int i = 0; i < Value.Length; i++) + { + writer.Write(Value[i]); + } + return sizeof(int) + sizeof(bool) * Value.Length; + } + + public override void FromString(string[] d, UAsset asset) + { + var valueList = new List(); + if (bool.TryParse(d[0], out bool res1)) valueList.Add(res1); + if (bool.TryParse(d[1], out bool res2)) valueList.Add(res2); + if (bool.TryParse(d[2], out bool res3)) valueList.Add(res3); + if (bool.TryParse(d[3], out bool res4)) valueList.Add(res4); + Value = valueList.ToArray(); + } + + public override string ToString() + { + string oup = "("; + for (int i = 0; i < Value.Length; i++) + { + oup += Convert.ToString(Value[i]) + ", "; + } + return oup.Remove(oup.Length - 2) + ")"; + } + } +} \ No newline at end of file diff --git a/Translation/UAssetAPI/PropertyTypes/Structs/PerPlatformFloatPropertyData.cs b/Translation/UAssetAPI/PropertyTypes/Structs/PerPlatformFloatPropertyData.cs new file mode 100644 index 0000000..5f516a4 --- /dev/null +++ b/Translation/UAssetAPI/PropertyTypes/Structs/PerPlatformFloatPropertyData.cs @@ -0,0 +1,78 @@ +using System; +using System.Collections.Generic; +using System.IO; +using UAssetAPI.PropertyTypes.Objects; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.PropertyTypes.Structs +{ + /// + /// () property with per-platform overrides. + /// + public class PerPlatformFloatPropertyData : PropertyData + { + public PerPlatformFloatPropertyData(FName name) : base(name) + { + + } + + public PerPlatformFloatPropertyData() + { + + } + + private static readonly FString CurrentPropertyType = new FString("PerPlatformFloat"); + public override bool HasCustomStructSerialization { get { return true; } } + public override FString PropertyType { get { return CurrentPropertyType; } } + + public override void Read(AssetBinaryReader reader, bool includeHeader, long leng1, long leng2 = 0) + { + if (includeHeader) + { + PropertyGuid = reader.ReadPropertyGuid(); + } + + int numEntries = reader.ReadInt32(); + Value = new float[numEntries]; + for (int i = 0; i < numEntries; i++) + { + Value[i] = reader.ReadSingle(); + } + } + + public override int Write(AssetBinaryWriter writer, bool includeHeader) + { + if (includeHeader) + { + writer.WritePropertyGuid(PropertyGuid); + } + + writer.Write(Value.Length); + for (int i = 0; i < Value.Length; i++) + { + writer.Write(Value[i]); + } + return sizeof(int) + sizeof(float) * Value.Length; + } + + public override void FromString(string[] d, UAsset asset) + { + var valueList = new List(); + if (float.TryParse(d[0], out float res1)) valueList.Add(res1); + if (float.TryParse(d[1], out float res2)) valueList.Add(res2); + if (float.TryParse(d[2], out float res3)) valueList.Add(res3); + if (float.TryParse(d[3], out float res4)) valueList.Add(res4); + Value = valueList.ToArray(); + } + + public override string ToString() + { + string oup = "("; + for (int i = 0; i < Value.Length; i++) + { + oup += Convert.ToString(Value[i]) + ", "; + } + return oup.Remove(oup.Length - 2) + ")"; + } + } +} \ No newline at end of file diff --git a/Translation/UAssetAPI/PropertyTypes/Structs/PerPlatformIntPropertyData.cs b/Translation/UAssetAPI/PropertyTypes/Structs/PerPlatformIntPropertyData.cs new file mode 100644 index 0000000..24c7795 --- /dev/null +++ b/Translation/UAssetAPI/PropertyTypes/Structs/PerPlatformIntPropertyData.cs @@ -0,0 +1,78 @@ +using System; +using System.Collections.Generic; +using System.IO; +using UAssetAPI.PropertyTypes.Objects; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.PropertyTypes.Structs +{ + /// + /// () property with per-platform overrides. + /// + public class PerPlatformIntPropertyData : PropertyData + { + public PerPlatformIntPropertyData(FName name) : base(name) + { + + } + + public PerPlatformIntPropertyData() + { + + } + + private static readonly FString CurrentPropertyType = new FString("PerPlatformInt"); + public override bool HasCustomStructSerialization { get { return true; } } + public override FString PropertyType { get { return CurrentPropertyType; } } + + public override void Read(AssetBinaryReader reader, bool includeHeader, long leng1, long leng2 = 0) + { + if (includeHeader) + { + PropertyGuid = reader.ReadPropertyGuid(); + } + + int numEntries = reader.ReadInt32(); + Value = new int[numEntries]; + for (int i = 0; i < numEntries; i++) + { + Value[i] = reader.ReadInt32(); + } + } + + public override int Write(AssetBinaryWriter writer, bool includeHeader) + { + if (includeHeader) + { + writer.WritePropertyGuid(PropertyGuid); + } + + writer.Write(Value.Length); + for (int i = 0; i < Value.Length; i++) + { + writer.Write(Value[i]); + } + return sizeof(int) + sizeof(int) * Value.Length; + } + + public override void FromString(string[] d, UAsset asset) + { + var valueList = new List(); + if (int.TryParse(d[0], out int res1)) valueList.Add(res1); + if (int.TryParse(d[1], out int res2)) valueList.Add(res2); + if (int.TryParse(d[2], out int res3)) valueList.Add(res3); + if (int.TryParse(d[3], out int res4)) valueList.Add(res4); + Value = valueList.ToArray(); + } + + public override string ToString() + { + string oup = "("; + for (int i = 0; i < Value.Length; i++) + { + oup += Convert.ToString(Value[i]) + ", "; + } + return oup.Remove(oup.Length - 2) + ")"; + } + } +} \ No newline at end of file diff --git a/Translation/UAssetAPI/PropertyTypes/Structs/QuatPropertyData.cs b/Translation/UAssetAPI/PropertyTypes/Structs/QuatPropertyData.cs new file mode 100644 index 0000000..7f5c2e2 --- /dev/null +++ b/Translation/UAssetAPI/PropertyTypes/Structs/QuatPropertyData.cs @@ -0,0 +1,67 @@ +using Newtonsoft.Json; +using System; +using System.IO; +using UAssetAPI.PropertyTypes.Objects; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.PropertyTypes.Structs +{ + /// + /// Floating point quaternion that can represent a rotation about an axis in 3-D space. + /// The X, Y, Z, W components also double as the Axis/Angle format. + /// + public class QuatPropertyData : PropertyData + { + public QuatPropertyData(FName name) : base(name) + { + + } + + public QuatPropertyData() + { + + } + + private static readonly FString CurrentPropertyType = new FString("Quat"); + public override bool HasCustomStructSerialization { get { return true; } } + public override FString PropertyType { get { return CurrentPropertyType; } } + + public override void Read(AssetBinaryReader reader, bool includeHeader, long leng1, long leng2 = 0) + { + if (includeHeader) + { + PropertyGuid = reader.ReadPropertyGuid(); + } + + Value = new FQuat(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle()); + } + + public override int Write(AssetBinaryWriter writer, bool includeHeader) + { + if (includeHeader) + { + writer.WritePropertyGuid(PropertyGuid); + } + + writer.Write(Value.X); + writer.Write(Value.Y); + writer.Write(Value.Z); + writer.Write(Value.W); + return sizeof(float) * 4; + } + + public override void FromString(string[] d, UAsset asset) + { + float.TryParse(d[0], out float X); + float.TryParse(d[1], out float Y); + float.TryParse(d[2], out float Z); + float.TryParse(d[3], out float W); + Value = new FQuat(X, Y, Z, W); + } + + public override string ToString() + { + return "(" + Value.X + ", " + Value.Y + ", " + Value.Z + ", " + Value.W + ")"; + } + } +} \ No newline at end of file diff --git a/Translation/UAssetAPI/PropertyTypes/Structs/RichCurveKeyPropertyData.cs b/Translation/UAssetAPI/PropertyTypes/Structs/RichCurveKeyPropertyData.cs new file mode 100644 index 0000000..562acf0 --- /dev/null +++ b/Translation/UAssetAPI/PropertyTypes/Structs/RichCurveKeyPropertyData.cs @@ -0,0 +1,133 @@ +using Newtonsoft.Json; +using System; +using System.IO; +using UAssetAPI.PropertyTypes.Objects; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.PropertyTypes.Structs +{ + public enum RichCurveInterpMode + { + Linear, + Constant, + Cubic, + None + } + + public enum RichCurveTangentMode + { + Auto, + User, + Break, + None + } + + public enum RichCurveTangentWeightMode + { + WeightedNone, + WeightedArrive, + WeightedLeave, + WeightedBoth + } + + public class RichCurveKeyPropertyData : PropertyData + { + [JsonProperty] + public RichCurveInterpMode InterpMode; + [JsonProperty] + public RichCurveTangentMode TangentMode; + [JsonProperty] + public RichCurveTangentWeightMode TangentWeightMode; + [JsonProperty] + public float Time; + [JsonProperty] + public float Value; + [JsonProperty] + public float ArriveTangent; + [JsonProperty] + public float ArriveTangentWeight; + [JsonProperty] + public float LeaveTangent; + [JsonProperty] + public float LeaveTangentWeight; + + public RichCurveKeyPropertyData(FName name) : base(name) + { + + } + + public RichCurveKeyPropertyData() + { + + } + + private static readonly FString CurrentPropertyType = new FString("RichCurveKey"); + public override bool HasCustomStructSerialization { get { return true; } } + public override FString PropertyType { get { return CurrentPropertyType; } } + + public override void Read(AssetBinaryReader reader, bool includeHeader, long leng1, long leng2 = 0) + { + if (includeHeader) + { + PropertyGuid = reader.ReadPropertyGuid(); + } + + InterpMode = (RichCurveInterpMode)reader.ReadSByte(); + TangentMode = (RichCurveTangentMode)reader.ReadSByte(); + TangentWeightMode = (RichCurveTangentWeightMode)reader.ReadSByte(); + Time = reader.ReadSingle(); + Value = reader.ReadSingle(); + ArriveTangent = reader.ReadSingle(); + ArriveTangentWeight = reader.ReadSingle(); + LeaveTangent = reader.ReadSingle(); + LeaveTangentWeight = reader.ReadSingle(); + } + + public override int Write(AssetBinaryWriter writer, bool includeHeader) + { + if (includeHeader) + { + writer.WritePropertyGuid(PropertyGuid); + } + + writer.Write((sbyte)InterpMode); + writer.Write((sbyte)TangentMode); + writer.Write((sbyte)TangentWeightMode); + writer.Write(Time); + writer.Write(Value); + writer.Write(ArriveTangent); + writer.Write(ArriveTangentWeight); + writer.Write(LeaveTangent); + writer.Write(LeaveTangentWeight); + return sizeof(float) * 6 + sizeof(sbyte) * 3; + } + + public override void FromString(string[] d, UAsset asset) + { + Enum.TryParse(d[0], out InterpMode); + Enum.TryParse(d[1], out TangentMode); + Enum.TryParse(d[2], out TangentWeightMode); + if (float.TryParse(d[3], out float res1)) Time = res1; + if (float.TryParse(d[4], out float res2)) Value = res2; + if (float.TryParse(d[5], out float res3)) ArriveTangent = res3; + if (float.TryParse(d[6], out float res4)) ArriveTangentWeight = res4; + if (float.TryParse(d[7], out float res5)) LeaveTangent = res5; + if (float.TryParse(d[8], out float res6)) LeaveTangentWeight = res6; + } + + public override string ToString() + { + string oup = "("; + oup += InterpMode + ", "; + oup += TangentMode + ", "; + oup += TangentWeightMode + ", "; + oup += Time + ", "; + oup += Value + ", "; + oup += ArriveTangent + ", "; + oup += ArriveTangentWeight + ", "; + oup += LeaveTangent + ", "; + oup += LeaveTangentWeight + ")"; + return oup; + } + } +} diff --git a/Translation/UAssetAPI/PropertyTypes/Structs/RotatorPropertyData.cs b/Translation/UAssetAPI/PropertyTypes/Structs/RotatorPropertyData.cs new file mode 100644 index 0000000..bab200e --- /dev/null +++ b/Translation/UAssetAPI/PropertyTypes/Structs/RotatorPropertyData.cs @@ -0,0 +1,66 @@ +using Newtonsoft.Json; +using System; +using System.IO; +using UAssetAPI.PropertyTypes.Objects; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.PropertyTypes.Structs +{ + /// + /// Implements a container for rotation information. + /// All rotation values are stored in degrees. + /// + public class RotatorPropertyData : PropertyData + { + public RotatorPropertyData(FName name) : base(name) + { + + } + + public RotatorPropertyData() + { + + } + + private static readonly FString CurrentPropertyType = new FString("Rotator"); + public override bool HasCustomStructSerialization { get { return true; } } + public override FString PropertyType { get { return CurrentPropertyType; } } + + public override void Read(AssetBinaryReader reader, bool includeHeader, long leng1, long leng2 = 0) + { + if (includeHeader) + { + PropertyGuid = reader.ReadPropertyGuid(); + } + + Value = new FRotator(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle()); + } + + public override int Write(AssetBinaryWriter writer, bool includeHeader) + { + if (includeHeader) + { + writer.WritePropertyGuid(PropertyGuid); + } + + writer.Write(Value.Pitch); + writer.Write(Value.Yaw); + writer.Write(Value.Roll); + return sizeof(float) * 3; + } + + public override void FromString(string[] d, UAsset asset) + { + float.TryParse(d[0], out float Pitch); + float.TryParse(d[1], out float Yaw); + float.TryParse(d[2], out float Roll); + Value = new FRotator(Pitch, Yaw, Roll); + } + + public override string ToString() + { + return "(" + Value.Pitch + ", " + Value.Yaw + ", " + Value.Roll + ")"; + + } + } +} \ No newline at end of file diff --git a/Translation/UAssetAPI/PropertyTypes/Structs/SkeletalMeshAreaWeightedTriangleSamplerPropertyData.cs b/Translation/UAssetAPI/PropertyTypes/Structs/SkeletalMeshAreaWeightedTriangleSamplerPropertyData.cs new file mode 100644 index 0000000..bf6d77c --- /dev/null +++ b/Translation/UAssetAPI/PropertyTypes/Structs/SkeletalMeshAreaWeightedTriangleSamplerPropertyData.cs @@ -0,0 +1,21 @@ +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.PropertyTypes.Structs +{ + public class SkeletalMeshAreaWeightedTriangleSamplerPropertyData : WeightedRandomSamplerPropertyData + { + public SkeletalMeshAreaWeightedTriangleSamplerPropertyData(FName name) : base(name) + { + + } + + public SkeletalMeshAreaWeightedTriangleSamplerPropertyData() + { + + } + + private static readonly FString CurrentPropertyType = new FString("SkeletalMeshAreaWeightedTriangleSampler"); + public override bool HasCustomStructSerialization { get { return true; } } + public override FString PropertyType { get { return CurrentPropertyType; } } + } +} \ No newline at end of file diff --git a/Translation/UAssetAPI/PropertyTypes/Structs/SkeletalMeshSamplingLODBuiltDataPropertyData.cs b/Translation/UAssetAPI/PropertyTypes/Structs/SkeletalMeshSamplingLODBuiltDataPropertyData.cs new file mode 100644 index 0000000..b229c66 --- /dev/null +++ b/Translation/UAssetAPI/PropertyTypes/Structs/SkeletalMeshSamplingLODBuiltDataPropertyData.cs @@ -0,0 +1,49 @@ +using System.IO; +using UAssetAPI.PropertyTypes.Objects; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.PropertyTypes.Structs +{ + public class SkeletalMeshSamplingLODBuiltDataPropertyData : PropertyData + { + public SkeletalMeshSamplingLODBuiltDataPropertyData(FName name) : base(name) + { + + } + + public SkeletalMeshSamplingLODBuiltDataPropertyData() + { + + } + + public override void Read(AssetBinaryReader reader, bool includeHeader, long leng1, long leng2 = 0) + { + if (includeHeader) + { + PropertyGuid = reader.ReadPropertyGuid(); + } + + Value = new SkeletalMeshAreaWeightedTriangleSamplerPropertyData(FName.DefineDummy(reader.Asset, "AreaWeightedTriangleSampler")); + Value.Read(reader, false, 0); + } + + public override int Write(AssetBinaryWriter writer, bool includeHeader) + { + if (includeHeader) + { + writer.WritePropertyGuid(PropertyGuid); + } + + return Value.Write(writer, false); + } + + private static readonly FString CurrentPropertyType = new FString("SkeletalMeshSamplingLODBuiltData"); + public override bool HasCustomStructSerialization { get { return true; } } + public override FString PropertyType { get { return CurrentPropertyType; } } + + public override string ToString() + { + return Value.ToString(); + } + } +} \ No newline at end of file diff --git a/Translation/UAssetAPI/PropertyTypes/Structs/SmartNamePropertyData.cs b/Translation/UAssetAPI/PropertyTypes/Structs/SmartNamePropertyData.cs new file mode 100644 index 0000000..0538881 --- /dev/null +++ b/Translation/UAssetAPI/PropertyTypes/Structs/SmartNamePropertyData.cs @@ -0,0 +1,93 @@ +using System; +using UAssetAPI.PropertyTypes.Objects; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.PropertyTypes.Structs +{ + /// + /// Special FName struct used within animations. + /// + public class SmartNamePropertyData : PropertyData + { + /// + /// The display name of this FSmartName. + /// + public FName DisplayName; + + /// + /// SmartName::UID_Type - for faster access + /// + public ushort SmartNameID; + + /// + /// Uncertain + /// + public Guid TempGUID; + + public SmartNamePropertyData(FName name) : base(name) + { + + } + + public SmartNamePropertyData() + { + + } + + private static readonly FString CurrentPropertyType = new FString("SmartName"); + public override bool HasCustomStructSerialization { get { return true; } } + public override FString PropertyType { get { return CurrentPropertyType; } } + + public override void Read(AssetBinaryReader reader, bool includeHeader, long leng1, long leng2 = 0) + { + if (includeHeader) + { + PropertyGuid = reader.ReadPropertyGuid(); + } + + DisplayName = reader.ReadFName(); + if (reader.Asset.GetCustomVersion() < FAnimPhysObjectVersion.RemoveUIDFromSmartNameSerialize) + { + SmartNameID = reader.ReadUInt16(); + } + if (reader.Asset.GetCustomVersion() < FAnimPhysObjectVersion.SmartNameRefactorForDeterministicCooking) + { + TempGUID = new Guid(reader.ReadBytes(16)); + } + } + + public override int Write(AssetBinaryWriter writer, bool includeHeader) + { + if (includeHeader) + { + writer.WritePropertyGuid(PropertyGuid); + } + + long here = writer.BaseStream.Position; + + writer.Write(DisplayName); + if (writer.Asset.GetCustomVersion() < FAnimPhysObjectVersion.RemoveUIDFromSmartNameSerialize) + { + writer.Write(SmartNameID); + } + if (writer.Asset.GetCustomVersion() < FAnimPhysObjectVersion.SmartNameRefactorForDeterministicCooking) + { + writer.Write(TempGUID.ToByteArray()); + } + + return (int)(writer.BaseStream.Position - here); + } + + public override void FromString(string[] d, UAsset asset) + { + DisplayName = FName.FromString(asset, d[0]); + if (ushort.TryParse(d[1], out ushort rawSmartNameID)) SmartNameID = rawSmartNameID; + TempGUID = d[2].ConvertToGUID(); + } + + public override string ToString() + { + return "(" + ")"; + } + } +} diff --git a/Translation/UAssetAPI/PropertyTypes/Structs/SoftAssetPathPropertyData.cs b/Translation/UAssetAPI/PropertyTypes/Structs/SoftAssetPathPropertyData.cs new file mode 100644 index 0000000..013b171 --- /dev/null +++ b/Translation/UAssetAPI/PropertyTypes/Structs/SoftAssetPathPropertyData.cs @@ -0,0 +1,21 @@ +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.PropertyTypes.Structs +{ + public class SoftAssetPathPropertyData : SoftObjectPathPropertyData + { + public SoftAssetPathPropertyData(FName name) : base(name) + { + + } + + public SoftAssetPathPropertyData() + { + + } + + private static readonly FString CurrentPropertyType = new FString("SoftAssetPath"); + public override bool HasCustomStructSerialization { get { return true; } } + public override FString PropertyType { get { return CurrentPropertyType; } } + } +} diff --git a/Translation/UAssetAPI/PropertyTypes/Structs/SoftClassPathPropertyData.cs b/Translation/UAssetAPI/PropertyTypes/Structs/SoftClassPathPropertyData.cs new file mode 100644 index 0000000..3b9eeb2 --- /dev/null +++ b/Translation/UAssetAPI/PropertyTypes/Structs/SoftClassPathPropertyData.cs @@ -0,0 +1,24 @@ +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.PropertyTypes.Structs +{ + /// + /// A struct that contains a string reference to a class. Can be used to make soft references to classes. + /// + public class SoftClassPathPropertyData : SoftObjectPathPropertyData + { + public SoftClassPathPropertyData(FName name) : base(name) + { + + } + + public SoftClassPathPropertyData() + { + + } + + private static readonly FString CurrentPropertyType = new FString("SoftClassPath"); + public override bool HasCustomStructSerialization { get { return true; } } + public override FString PropertyType { get { return CurrentPropertyType; } } + } +} diff --git a/Translation/UAssetAPI/PropertyTypes/Structs/SoftObjectPathPropertyData.cs b/Translation/UAssetAPI/PropertyTypes/Structs/SoftObjectPathPropertyData.cs new file mode 100644 index 0000000..3c3b080 --- /dev/null +++ b/Translation/UAssetAPI/PropertyTypes/Structs/SoftObjectPathPropertyData.cs @@ -0,0 +1,104 @@ +using Newtonsoft.Json; +using UAssetAPI.PropertyTypes.Objects; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.PropertyTypes.Structs +{ + /// + /// A struct that contains a string reference to an object, either a top level asset or a subobject. + /// This can be used to make soft references to assets that are loaded on demand. + /// This is stored internally as an FName pointing to the top level asset (/package/path.assetname) and an option a string subobject path. + /// + public class SoftObjectPathPropertyData : PropertyData + { + /// Asset path, patch to a top level object in a package. This is /package/path.assetname + [JsonProperty] + public FName AssetPathName; + + /// Optional FString for subobject within an asset. This is the sub path after the : + [JsonProperty] + public FString SubPathString; + + /// Used in older versions of the Unreal Engine. + [JsonProperty] + public FString Path; + + public SoftObjectPathPropertyData(FName name) : base(name) + { + + } + + public SoftObjectPathPropertyData() + { + + } + + private static readonly FString CurrentPropertyType = new FString("SoftObjectPath"); + public override bool HasCustomStructSerialization { get { return true; } } + public override FString PropertyType { get { return CurrentPropertyType; } } + + public override void Read(AssetBinaryReader reader, bool includeHeader, long leng1, long leng2 = 0) + { + if (includeHeader) + { + PropertyGuid = reader.ReadPropertyGuid(); + } + + if (reader.Asset.EngineVersion < UE4Version.VER_UE4_ADDED_SOFT_OBJECT_PATH) + { + Path = reader.ReadFString(); + } + else + { + AssetPathName = reader.ReadFName(); + SubPathString = reader.ReadFString(); + } + } + + public override int Write(AssetBinaryWriter writer, bool includeHeader) + { + if (includeHeader) + { + writer.WritePropertyGuid(PropertyGuid); + } + + int here = (int)writer.BaseStream.Position; + + if (writer.Asset.EngineVersion < UE4Version.VER_UE4_ADDED_SOFT_OBJECT_PATH) + { + writer.Write(Path); + } + else + { + writer.Write(AssetPathName); + writer.Write(SubPathString); + } + + return (int)writer.BaseStream.Position - here; + } + + public override string ToString() + { + return "(" + AssetPathName.ToString() + ", " + SubPathString.ToString() + ")"; + } + + public override void FromString(string[] d, UAsset asset) + { + if (asset.EngineVersion < UE4Version.VER_UE4_ADDED_SOFT_OBJECT_PATH) + { + Path = FString.FromString(d[0]); + } + else + { + FName output = FName.FromString(asset, d[0]); + asset.AddNameReference(output.Value); + AssetPathName = output; + + if (d.Length > 1) + { + SubPathString = FString.FromString(d[1]); + } + } + } + } +} diff --git a/Translation/UAssetAPI/PropertyTypes/Structs/StructPropertyData.cs b/Translation/UAssetAPI/PropertyTypes/Structs/StructPropertyData.cs new file mode 100644 index 0000000..9c79de0 --- /dev/null +++ b/Translation/UAssetAPI/PropertyTypes/Structs/StructPropertyData.cs @@ -0,0 +1,152 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.IO; +using UAssetAPI.PropertyTypes.Objects; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.PropertyTypes.Structs +{ + public class StructPropertyData : PropertyData> // List + { + [JsonProperty] + public FName StructType = null; + [JsonProperty] + public bool SerializeNone = true; + [JsonProperty] + public Guid StructGUID = Guid.Empty; // usually set to 0 + + public StructPropertyData(FName name) : base(name) + { + Value = new List(); + } + + public StructPropertyData(FName name, FName forcedType) : base(name) + { + StructType = forcedType; + Value = new List(); + } + + public StructPropertyData() + { + + } + + private static readonly FString CurrentPropertyType = new FString("StructProperty"); + public override FString PropertyType { get { return CurrentPropertyType; } } + + private void ReadOnce(AssetBinaryReader reader, Type T, long offset) + { + var data = Activator.CreateInstance(T, Name) as PropertyData; + if (data == null) return; + data.Offset = offset; + data.Read(reader, false, 0); + Value = new List { data }; + } + + private void ReadNTPL(AssetBinaryReader reader) + { + List resultingList = new List(); + PropertyData data = null; + while ((data = MainSerializer.Read(reader, true)) != null) + { + resultingList.Add(data); + } + + Value = resultingList; + } + + public override void Read(AssetBinaryReader reader, bool includeHeader, long leng1, long leng2 = 0) + { + if (includeHeader) // originally !isForced + { + StructType = reader.ReadFName(); + if (reader.Asset.EngineVersion >= UE4Version.VER_UE4_STRUCT_GUID_IN_PROPERTY_TAG) StructGUID = new Guid(reader.ReadBytes(16)); + PropertyGuid = reader.ReadPropertyGuid(); + } + + MainSerializer.PropertyTypeRegistry.TryGetValue(StructType.Value.Value, out RegistryEntry targetEntry); + bool hasCustomStructSerialization = targetEntry != null && targetEntry.HasCustomStructSerialization; + + if (StructType.Value.Value == "RichCurveKey" && reader.Asset.EngineVersion < UE4Version.VER_UE4_SERIALIZE_RICH_CURVE_KEY) hasCustomStructSerialization = false; + if (StructType.Value.Value == "MovieSceneTrackIdentifier" && reader.Asset.GetCustomVersion() < FEditorObjectVersion.MovieSceneMetaDataSerialization) hasCustomStructSerialization = false; + + if (leng1 == 0) + { + SerializeNone = false; + Value = new List(); + return; + } + + if (targetEntry != null && hasCustomStructSerialization) + { + ReadOnce(reader, targetEntry.PropertyType, reader.BaseStream.Position); + } + else + { + ReadNTPL(reader); + } + } + + private int WriteOnce(AssetBinaryWriter writer) + { + if (Value.Count != 1) throw new InvalidOperationException("Structs with type " + StructType.Value.Value + " must have exactly one entry"); + Value[0].Offset = writer.BaseStream.Position; + return Value[0].Write(writer, false); + } + + private int WriteNTPL(AssetBinaryWriter writer) + { + int here = (int)writer.BaseStream.Position; + if (Value != null) + { + foreach (var t in Value) + { + MainSerializer.Write(t, writer, true); + } + } + writer.Write(new FName(writer.Asset, "None")); + return (int)writer.BaseStream.Position - here; + } + + public override int Write(AssetBinaryWriter writer, bool includeHeader) + { + if (includeHeader) + { + writer.Write(StructType); + if (writer.Asset.EngineVersion >= UE4Version.VER_UE4_STRUCT_GUID_IN_PROPERTY_TAG) writer.Write(StructGUID.ToByteArray()); + writer.WritePropertyGuid(PropertyGuid); + } + + MainSerializer.PropertyTypeRegistry.TryGetValue(StructType.Value.Value, out RegistryEntry targetEntry); + bool hasCustomStructSerialization = targetEntry != null && targetEntry.HasCustomStructSerialization; + + if (StructType.Value.Value == "RichCurveKey" && writer.Asset.EngineVersion < UE4Version.VER_UE4_SERIALIZE_RICH_CURVE_KEY) hasCustomStructSerialization = false; + if (StructType.Value.Value == "MovieSceneTrackIdentifier" && writer.Asset.GetCustomVersion() < FEditorObjectVersion.MovieSceneMetaDataSerialization) hasCustomStructSerialization = false; + + if (targetEntry != null && hasCustomStructSerialization) return WriteOnce(writer); + if (Value.Count == 0 && !SerializeNone) return 0; + return WriteNTPL(writer); + } + + public override void FromString(string[] d, UAsset asset) + { + if (d[4] != null && d[4] != "Generic") StructType = FName.FromString(asset, d[4]); + if (StructType == null) StructType = FName.DefineDummy(asset, "Generic"); + } + + protected override void HandleCloned(PropertyData res) + { + StructPropertyData cloningProperty = (StructPropertyData)res; + cloningProperty.StructType = (FName)this.StructType.Clone(); + cloningProperty.StructGUID = new Guid(this.StructGUID.ToByteArray()); + + List newData = new List(this.Value.Count); + for (int i = 0; i < this.Value.Count; i++) + { + newData.Add((PropertyData)this.Value[i].Clone()); + } + cloningProperty.Value = newData; + } + } +} \ No newline at end of file diff --git a/Translation/UAssetAPI/PropertyTypes/Structs/TimespanPropertyData.cs b/Translation/UAssetAPI/PropertyTypes/Structs/TimespanPropertyData.cs new file mode 100644 index 0000000..86adac8 --- /dev/null +++ b/Translation/UAssetAPI/PropertyTypes/Structs/TimespanPropertyData.cs @@ -0,0 +1,72 @@ +using System; +using System.IO; +using UAssetAPI.PropertyTypes.Objects; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.PropertyTypes.Structs +{ + /// + /// Implements a time span. + /// A time span is the difference between two dates and times. For example, the time span between + /// 12:00:00 January 1, 2000 and 18:00:00 January 2, 2000 is 30.0 hours. Time spans are measured in + /// positive or negative ticks depending on whether the difference is measured forward or backward. + /// Each tick has a resolution of 0.1 microseconds (= 100 nanoseconds). + /// + /// In conjunction with the companion class (), + /// time spans can be used to perform date and time based arithmetic, such as calculating the + /// difference between two dates or adding a certain amount of time to a given date. + /// + public class TimespanPropertyData : PropertyData + { + public TimespanPropertyData(FName name) : base(name) + { + + } + + public TimespanPropertyData() + { + + } + + private static readonly FString CurrentPropertyType = new FString("Timespan"); + public override bool HasCustomStructSerialization { get { return true; } } + public override FString PropertyType { get { return CurrentPropertyType; } } + + public override void Read(AssetBinaryReader reader, bool includeHeader, long leng1, long leng2 = 0) + { + if (includeHeader) + { + PropertyGuid = reader.ReadPropertyGuid(); + } + + Value = new TimeSpan(reader.ReadInt64()); // number of ticks + } + + public override int Write(AssetBinaryWriter writer, bool includeHeader) + { + if (includeHeader) + { + writer.WritePropertyGuid(PropertyGuid); + } + + writer.Write(Value.Ticks); + return sizeof(long); + } + + public override void FromString(string[] d, UAsset asset) + { + Value = TimeSpan.Parse(d[0]); + } + + public override string ToString() + { + return Value.ToString(); + } + + protected override void HandleCloned(PropertyData res) + { + TimespanPropertyData cloningProperty = (TimespanPropertyData)res; + cloningProperty.Value = new TimeSpan(cloningProperty.Value.Ticks); + } + } +} \ No newline at end of file diff --git a/Translation/UAssetAPI/PropertyTypes/Structs/Vector2DPropertyData.cs b/Translation/UAssetAPI/PropertyTypes/Structs/Vector2DPropertyData.cs new file mode 100644 index 0000000..2b8556d --- /dev/null +++ b/Translation/UAssetAPI/PropertyTypes/Structs/Vector2DPropertyData.cs @@ -0,0 +1,70 @@ +using Newtonsoft.Json; +using System; +using System.IO; +using UAssetAPI.PropertyTypes.Objects; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.PropertyTypes.Structs +{ + /// + /// A vector in 2-D space composed of components (X, Y) with floating point precision. + /// + public class Vector2DPropertyData : PropertyData + { + /// Vector's X-component. + [JsonProperty] + public float X; + + /// Vector's Y-component. + [JsonProperty] + public float Y; + + public Vector2DPropertyData(FName name) : base(name) + { + + } + + public Vector2DPropertyData() + { + + } + + private static readonly FString CurrentPropertyType = new FString("Vector2D"); + public override bool HasCustomStructSerialization { get { return true; } } + public override FString PropertyType { get { return CurrentPropertyType; } } + + public override void Read(AssetBinaryReader reader, bool includeHeader, long leng1, long leng2 = 0) + { + if (includeHeader) + { + PropertyGuid = reader.ReadPropertyGuid(); + } + + X = reader.ReadSingle(); + Y = reader.ReadSingle(); + } + + public override int Write(AssetBinaryWriter writer, bool includeHeader) + { + if (includeHeader) + { + writer.WritePropertyGuid(PropertyGuid); + } + + writer.Write(X); + writer.Write(Y); + return sizeof(float) * 2; + } + + public override void FromString(string[] d, UAsset asset) + { + if (float.TryParse(d[0], out float res1)) X = res1; + if (float.TryParse(d[1], out float res2)) Y = res2; + } + + public override string ToString() + { + return "(" + X + ", " + Y + ")"; + } + } +} \ No newline at end of file diff --git a/Translation/UAssetAPI/PropertyTypes/Structs/Vector4PropertyData.cs b/Translation/UAssetAPI/PropertyTypes/Structs/Vector4PropertyData.cs new file mode 100644 index 0000000..5f401ec --- /dev/null +++ b/Translation/UAssetAPI/PropertyTypes/Structs/Vector4PropertyData.cs @@ -0,0 +1,84 @@ +using Newtonsoft.Json; +using System; +using System.IO; +using UAssetAPI.PropertyTypes.Objects; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.PropertyTypes.Structs +{ + /// + /// A 4D homogeneous vector, 4x1 FLOATs, 16-byte aligned. + /// + public class Vector4PropertyData : PropertyData + { + /// Vector's X-component. + [JsonProperty] + public float X; + + /// Vector's Y-component. + [JsonProperty] + public float Y; + + /// Vector's Z-component. + [JsonProperty] + public float Z; + + /// Vector's W-component. + [JsonProperty] + public float W; + + public Vector4PropertyData(FName name) : base(name) + { + + } + + public Vector4PropertyData() + { + + } + + private static readonly FString CurrentPropertyType = new FString("Vector4"); + public override bool HasCustomStructSerialization { get { return true; } } + public override FString PropertyType { get { return CurrentPropertyType; } } + + public override void Read(AssetBinaryReader reader, bool includeHeader, long leng1, long leng2 = 0) + { + if (includeHeader) + { + PropertyGuid = reader.ReadPropertyGuid(); + } + + X = reader.ReadSingle(); + Y = reader.ReadSingle(); + Z = reader.ReadSingle(); + W = reader.ReadSingle(); + } + + public override int Write(AssetBinaryWriter writer, bool includeHeader) + { + if (includeHeader) + { + writer.WritePropertyGuid(PropertyGuid); + } + + writer.Write(X); + writer.Write(Y); + writer.Write(Z); + writer.Write(W); + return sizeof(float) * 4; + } + + public override void FromString(string[] d, UAsset asset) + { + if (float.TryParse(d[0], out float res1)) X = res1; + if (float.TryParse(d[1], out float res2)) Y = res2; + if (float.TryParse(d[2], out float res3)) Z = res3; + if (float.TryParse(d[3], out float res4)) W = res4; + } + + public override string ToString() + { + return "(" + X + ", " + Y + ", " + Z + ", " + W + ")"; + } + } +} \ No newline at end of file diff --git a/Translation/UAssetAPI/PropertyTypes/Structs/VectorPropertyData.cs b/Translation/UAssetAPI/PropertyTypes/Structs/VectorPropertyData.cs new file mode 100644 index 0000000..b82e96d --- /dev/null +++ b/Translation/UAssetAPI/PropertyTypes/Structs/VectorPropertyData.cs @@ -0,0 +1,64 @@ +using Newtonsoft.Json; +using System; +using System.IO; +using UAssetAPI.PropertyTypes.Objects; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.PropertyTypes.Structs +{ + /// + /// A vector in 3-D space composed of components (X, Y, Z) with floating point precision. + /// + public class VectorPropertyData : PropertyData + { + public VectorPropertyData(FName name) : base(name) + { + + } + + public VectorPropertyData() + { + + } + + private static readonly FString CurrentPropertyType = new FString("Vector"); + public override bool HasCustomStructSerialization { get { return true; } } + public override FString PropertyType { get { return CurrentPropertyType; } } + + public override void Read(AssetBinaryReader reader, bool includeHeader, long leng1, long leng2 = 0) + { + if (includeHeader) + { + PropertyGuid = reader.ReadPropertyGuid(); + } + + Value = new FVector(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle()); + } + + public override int Write(AssetBinaryWriter writer, bool includeHeader) + { + if (includeHeader) + { + writer.WritePropertyGuid(PropertyGuid); + } + + writer.Write(Value.X); + writer.Write(Value.Y); + writer.Write(Value.Z); + return sizeof(float) * 3; + } + + public override void FromString(string[] d, UAsset asset) + { + float.TryParse(d[0], out float X); + float.TryParse(d[1], out float Y); + float.TryParse(d[2], out float Z); + Value = new FVector(X, Y, Z); + } + + public override string ToString() + { + return "(" + Value.X + ", " + Value.Y + ", " + Value.Z + ")"; + } + } +} \ No newline at end of file diff --git a/Translation/UAssetAPI/PropertyTypes/Structs/ViewTargetBlendParamsPropertyData.cs b/Translation/UAssetAPI/PropertyTypes/Structs/ViewTargetBlendParamsPropertyData.cs new file mode 100644 index 0000000..816c534 --- /dev/null +++ b/Translation/UAssetAPI/PropertyTypes/Structs/ViewTargetBlendParamsPropertyData.cs @@ -0,0 +1,103 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; +using System; +using System.IO; +using UAssetAPI.PropertyTypes.Objects; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.PropertyTypes.Structs +{ + /// + /// Options that define how to blend when changing view targets in . + /// + public enum ViewTargetBlendFunction + { + /** Camera does a simple linear interpolation. */ + VTBlend_Linear, + /** Camera has a slight ease in and ease out, but amount of ease cannot be tweaked. */ + VTBlend_Cubic, + /** Camera immediately accelerates, but smoothly decelerates into the target. Ease amount controlled by BlendExp. */ + VTBlend_EaseIn, + /** Camera smoothly accelerates, but does not decelerate into the target. Ease amount controlled by BlendExp. */ + VTBlend_EaseOut, + /** Camera smoothly accelerates and decelerates. Ease amount controlled by BlendExp. */ + VTBlend_EaseInOut, + VTBlend_MAX, + } + + /// + /// A set of parameters to describe how to transition between view targets. + /// Referred to as FViewTargetTransitionParams in the Unreal Engine. + /// + public class ViewTargetBlendParamsPropertyData : PropertyData + { + [JsonProperty] + public float BlendTime; + [JsonProperty] + [JsonConverter(typeof(StringEnumConverter))] + public ViewTargetBlendFunction BlendFunction; + [JsonProperty] + public float BlendExp; + [JsonProperty] + public bool bLockOutgoing; + + public ViewTargetBlendParamsPropertyData(FName name) : base(name) + { + + } + + public ViewTargetBlendParamsPropertyData() + { + + } + + private static readonly FString CurrentPropertyType = new FString("ViewTargetBlendParams"); + public override bool HasCustomStructSerialization { get { return true; } } + public override FString PropertyType { get { return CurrentPropertyType; } } + + public override void Read(AssetBinaryReader reader, bool includeHeader, long leng1, long leng2 = 0) + { + if (includeHeader) + { + PropertyGuid = reader.ReadPropertyGuid(); + } + + BlendTime = reader.ReadSingle(); + BlendFunction = (ViewTargetBlendFunction)reader.ReadByte(); + BlendExp = reader.ReadSingle(); + bLockOutgoing = reader.ReadInt32() != 0; + } + + public override int Write(AssetBinaryWriter writer, bool includeHeader) + { + if (includeHeader) + { + writer.WritePropertyGuid(PropertyGuid); + } + + writer.Write(BlendTime); + writer.Write((byte)BlendFunction); + writer.Write(BlendExp); + writer.Write(bLockOutgoing ? 1 : 0); + return sizeof(float) * 2 + sizeof(byte) + sizeof(int); + } + + public override void FromString(string[] d, UAsset asset) + { + if (float.TryParse(d[0], out float res1)) BlendTime = res1; + if (Enum.TryParse(d[1], out ViewTargetBlendFunction res2)) BlendFunction = res2; + if (float.TryParse(d[2], out float res3)) BlendExp = res3; + if (bool.TryParse(d[3], out bool res4)) bLockOutgoing = res4; + } + + public override string ToString() + { + string oup = "("; + oup += BlendTime + ", "; + oup += BlendFunction + ", "; + oup += BlendExp + ", "; + oup += bLockOutgoing + ", "; + return oup.Remove(oup.Length - 2) + ")"; + } + } +} diff --git a/Translation/UAssetAPI/PropertyTypes/Structs/WeightedRandomSamplerPropertyData.cs b/Translation/UAssetAPI/PropertyTypes/Structs/WeightedRandomSamplerPropertyData.cs new file mode 100644 index 0000000..7ddf947 --- /dev/null +++ b/Translation/UAssetAPI/PropertyTypes/Structs/WeightedRandomSamplerPropertyData.cs @@ -0,0 +1,115 @@ +using Newtonsoft.Json; +using System; +using System.IO; +using UAssetAPI.PropertyTypes.Objects; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.PropertyTypes.Structs +{ + public class WeightedRandomSamplerPropertyData : PropertyData + { + [JsonProperty] + public float[] Prob; + [JsonProperty] + public int[] Alias; + [JsonProperty] + public float TotalWeight; + + public WeightedRandomSamplerPropertyData(FName name) : base(name) + { + + } + + public WeightedRandomSamplerPropertyData() + { + + } + + private static readonly FString CurrentPropertyType = new FString("WeightedRandomSampler"); + public override bool HasCustomStructSerialization { get { return true; } } + public override FString PropertyType { get { return CurrentPropertyType; } } + + public override void Read(AssetBinaryReader reader, bool includeHeader, long leng1, long leng2 = 0) + { + if (includeHeader) + { + PropertyGuid = reader.ReadPropertyGuid(); + } + + int size = reader.ReadInt32(); + Prob = new float[size]; + for (int i = 0; i < size; i++) + { + Prob[i] = reader.ReadSingle(); + } + + size = reader.ReadInt32(); + Alias = new int[size]; + for (int i = 0; i < size; i++) + { + Alias[i] = reader.ReadInt32(); + } + + TotalWeight = reader.ReadSingle(); + } + + public override int Write(AssetBinaryWriter writer, bool includeHeader) + { + if (includeHeader) + { + writer.WritePropertyGuid(PropertyGuid); + } + + writer.Write(Prob.Length); + for (int i = 0; i < Prob.Length; i++) + { + writer.Write(Prob[i]); + } + + writer.Write(Alias.Length); + for (int i = 0; i < Alias.Length; i++) + { + writer.Write(Alias[i]); + } + + writer.Write(TotalWeight); + + return sizeof(int) + sizeof(float) * Prob.Length + sizeof(int) + sizeof(int) * Alias.Length + sizeof(float); + } + + public override void FromString(string[] d, UAsset asset) + { + + } + + public override string ToString() + { + string oup = "("; + + oup += "("; + for (int i = 0; i < Prob.Length; i++) + { + oup += Convert.ToString(Prob[i]) + ", "; + } + oup = oup.Remove(oup.Length - 2) + ")"; + + oup += "("; + for (int i = 0; i < Alias.Length; i++) + { + oup += Convert.ToString(Alias[i]) + ", "; + } + oup = oup.Remove(oup.Length - 2) + ")"; + + oup += ", " + TotalWeight + ")"; + + return oup; + } + + protected override void HandleCloned(PropertyData res) + { + WeightedRandomSamplerPropertyData cloningProperty = (WeightedRandomSamplerPropertyData)res; + cloningProperty.Prob = (float[])this.Prob.Clone(); + cloningProperty.Alias = (int[])this.Alias.Clone(); + } + } +} \ No newline at end of file diff --git a/Translation/UAssetAPI/Resources/AC7Key.bin b/Translation/UAssetAPI/Resources/AC7Key.bin new file mode 100644 index 0000000..7ddcf6e Binary files /dev/null and b/Translation/UAssetAPI/Resources/AC7Key.bin differ diff --git a/Translation/UAssetAPI/UAPUtils.cs b/Translation/UAssetAPI/UAPUtils.cs new file mode 100644 index 0000000..dd5c340 --- /dev/null +++ b/Translation/UAssetAPI/UAPUtils.cs @@ -0,0 +1,159 @@ +using Newtonsoft.Json; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Reflection; +using UAssetAPI.PropertyTypes.Objects; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI +{ + public static class UAPUtils + { + public static string CurrentCommit = string.Empty; + + public static string SerializeJson(object obj, Formatting jsonFormatting = Formatting.None) + { + return JsonConvert.SerializeObject(obj, jsonFormatting, UAsset.jsonSettings); + } + + public static List FindAllInstances(object parent) where T : class + { + HashSet yaExplorado = new HashSet(); + List res = new List(); + + FindAllInstances(parent, yaExplorado, res); + + return res; + } + + private static void FindAllInstances(object value, HashSet yaExplorado, List res) where T : class + { + if (value == null) return; + if (yaExplorado.Contains(value)) return; + + yaExplorado.Add(value); + + if (value is IEnumerable enumerable) + { + foreach (object item in enumerable) + { + FindAllInstances(item, yaExplorado, res); + } + } + else + { + if (value is T match) res.Add(match); + + PropertyInfo[] properties = value.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.GetProperty); + foreach (PropertyInfo property in properties) + { + if (property.GetIndexParameters().Length > 0) continue; + if (value is PropertyData && (property.Name == "PropertyType" || property.Name == "HasCustomStructSerialization")) continue; + FindAllInstances(property.GetValue(value, null), yaExplorado, res); + } + + FieldInfo[] fields = value.GetType().GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); + foreach (FieldInfo field in fields) + { + FindAllInstances(field.GetValue(value), yaExplorado, res); + } + } + } + + public static T Clamp(T val, T min, T max) where T : IComparable + { + if (val.CompareTo(min) < 0) return min; + else if (val.CompareTo(max) > 0) return max; + else return val; + } + + public static FieldInfo[] GetOrderedFields() + { + return typeof(T).GetFields().Where(fld => fld.IsDefined(typeof(DisplayIndexOrderAttribute), true)).OrderBy(fld => ((DisplayIndexOrderAttribute[])fld.GetCustomAttributes(typeof(DisplayIndexOrderAttribute), true))[0].DisplayingIndex).ToArray(); + } + + public static FieldInfo[] GetOrderedFields(Type t) + { + return t.GetFields().Where(fld => fld.IsDefined(typeof(DisplayIndexOrderAttribute), true)).OrderBy(fld => ((DisplayIndexOrderAttribute[])fld.GetCustomAttributes(typeof(DisplayIndexOrderAttribute), true))[0].DisplayingIndex).ToArray(); + } + + public static FString GetImportNameReferenceWithoutZero(int j, UAsset asset) + { + FString refer = new FPackageIndex(j).ToImport(asset).ObjectName.Value; + if (!asset.ContainsNameReference(refer)) return refer; + return asset.GetNameReferenceWithoutZero(asset.SearchNameReference(refer)); + } + + public static uint[] InterpretAsGuidAndConvertToUnsignedInts(this string value) + { + Guid res = value.Trim().ConvertToGUID(); + return res.ToUnsignedInts(); + } + + public static uint[] ToUnsignedInts(this Guid value) + { + byte[] vals = value.ToByteArray(); + uint[] res = new uint[4]; + res[0] = BitConverter.ToUInt32(vals, 0); + res[1] = BitConverter.ToUInt32(vals, sizeof(uint)); + res[2] = BitConverter.ToUInt32(vals, sizeof(uint) * 2); + res[3] = BitConverter.ToUInt32(vals, sizeof(uint) * 3); + return res; + } + + public static Guid GUID(uint value1, uint value2, uint value3, uint value4) + { + byte[] bytes = new byte[16]; + BitConverter.GetBytes(value1).CopyTo(bytes, 0); + BitConverter.GetBytes(value2).CopyTo(bytes, sizeof(uint)); + BitConverter.GetBytes(value3).CopyTo(bytes, sizeof(uint) * 2); + BitConverter.GetBytes(value4).CopyTo(bytes, sizeof(uint) * 3); + return new Guid(bytes); + } + + public static Guid ConvertToGUID(this string GuidString) + { + if (GuidString == null || + (GuidString[0] != '{') || + (GuidString[9] != '-') || + (GuidString[14] != '-') || + (GuidString[19] != '-') || + (GuidString[24] != '-') || + (GuidString[37] != '}')) + { + if (Guid.TryParse(GuidString, out Guid res1)) return res1; + return Guid.Empty; + } + + string byteText = GuidString.Substring(29, 8) + GuidString.Substring(20, 4) + GuidString.Substring(25, 4) + GuidString.Substring(10, 4) + GuidString.Substring(15, 4) + GuidString.Substring(1, 8); + byte[] byteArr = ConvertHexStringToByteArray(byteText); + Array.Reverse(byteArr); + return new Guid(byteArr); + } + + public static string ConvertToString(this Guid val) + { + byte[] byteArr = val.ToByteArray(); + Array.Reverse(byteArr); + string bytes = BitConverter.ToString(byteArr).Replace("-", ""); + return ("{" + bytes.Substring(24, 8) + "-" + bytes.Substring(16, 4) + "-" + bytes.Substring(20, 4) + "-" + bytes.Substring(8, 4) + "-" + bytes.Substring(12, 4) + bytes.Substring(0, 8) + "}").ToUpperInvariant(); + } + + public static byte[] ConvertHexStringToByteArray(string hexString) + { + hexString = hexString.Replace(" ", string.Empty).Replace("-", string.Empty); + + byte[] data = new byte[hexString.Length / 2]; + for (int index = 0; index < data.Length; index++) + { + string byteValue = hexString.Substring(index * 2, 2); + data[index] = byte.Parse(byteValue, NumberStyles.HexNumber, CultureInfo.InvariantCulture); + } + + return data; + } + } +} diff --git a/Translation/UAssetAPI/UAsset.cs b/Translation/UAssetAPI/UAsset.cs new file mode 100644 index 0000000..11bb2c6 --- /dev/null +++ b/Translation/UAssetAPI/UAsset.cs @@ -0,0 +1,1856 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using UAssetAPI.FieldTypes; +using UAssetAPI.JSON; +using UAssetAPI.PropertyTypes.Objects; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI +{ + public class NameMapOutOfRangeException : FormatException + { + public FString RequiredName; + + public NameMapOutOfRangeException(FString requiredName) : base("Requested name \"" + requiredName + "\" not found in name map") + { + RequiredName = requiredName; + } + } + + public class UnknownEngineVersionException : InvalidOperationException + { + public UnknownEngineVersionException(string message) : base(message) + { + + } + } + + /// + /// Holds basic Unreal version numbers. + /// + public struct FEngineVersion + { + /// Major version number. + public ushort Major; + /// Minor version number. + public ushort Minor; + /// Patch version number. + public ushort Patch; + /// Changelist number. This is used by the engine to arbitrate when Major/Minor/Patch version numbers match. + public uint Changelist; + /// Branch name. + public FString Branch; + + public void Write(AssetBinaryWriter writer) + { + writer.Write(Major); + writer.Write(Minor); + writer.Write(Patch); + writer.Write(Changelist); + writer.Write(Branch); + } + + public FEngineVersion(AssetBinaryReader reader) + { + Major = reader.ReadUInt16(); + Minor = reader.ReadUInt16(); + Patch = reader.ReadUInt16(); + Changelist = reader.ReadUInt32(); + Branch = reader.ReadFString(); + } + + public FEngineVersion(ushort major, ushort minor, ushort patch, uint changelist, FString branch) + { + Major = major; + Minor = minor; + Patch = patch; + Changelist = changelist; + Branch = branch; + } + } + + /// + /// Revision data for an Unreal package file. + /// + public class FGenerationInfo + { + /// Number of exports in the export map for this generation. + public int ExportCount; + /// Number of names in the name map for this generation. + public int NameCount; + + public FGenerationInfo(int exportCount, int nameCount) + { + ExportCount = exportCount; + NameCount = nameCount; + } + } + + public class UAsset + { + /// + /// Agent string to provide context in serialized JSON. + /// + [JsonProperty(Order = -99)] + public string Info = "Serialized with UAssetAPI"; + + /// + /// The path of the file on disk that this asset represents. This does not need to be specified for regular parsing. + /// + [JsonIgnore] + public string FilePath; + + /// + /// Should the asset be split into separate .uasset, .uexp, and .ubulk files, as opposed to one single .uasset file? + /// + public bool UseSeparateBulkDataFiles = false; + + /// + /// The version of the Unreal Engine that will be used to parse this asset. + /// + public UE4Version EngineVersion = UE4Version.UNKNOWN; + + /// + /// Checks whether or not this asset maintains binary equality when serialized. + /// + /// Whether or not the asset maintained binary equality. + public bool VerifyBinaryEquality() + { + MemoryStream f = this.PathToStream(FilePath); + f.Seek(0, SeekOrigin.Begin); + MemoryStream newDataStream = WriteData(); + f.Seek(0, SeekOrigin.Begin); + + if (f.Length != newDataStream.Length) return false; + + const int CHUNK_SIZE = 1024; + byte[] buffer = new byte[CHUNK_SIZE]; + byte[] buffer2 = new byte[CHUNK_SIZE]; + int lastRead1; + while ((lastRead1 = f.Read(buffer, 0, buffer.Length)) > 0) + { + int lastRead2 = newDataStream.Read(buffer2, 0, buffer2.Length); + if (lastRead1 != lastRead2) return false; + if (!buffer.SequenceEqual(buffer2)) return false; + } + + return true; + } + + private void FixNameMapLookupIfNeeded() + { + if (nameMapIndexList.Count > 0 && nameMapLookup.Count == 0) + { + for (int i = 0; i < nameMapIndexList.Count; i++) + { + nameMapLookup[nameMapIndexList[i].Value] = i; + } + } + } + + /// + /// Returns the name map as a read-only list of FStrings. + /// + /// The name map as a read-only list of FStrings. + public IReadOnlyList GetNameMapIndexList() + { + FixNameMapLookupIfNeeded(); + return nameMapIndexList.AsReadOnly(); + } + + /// + /// Clears the name map. This method should be used with extreme caution, as it may break unparsed references to the name map. + /// + public void ClearNameIndexList() + { + nameMapIndexList = new List(); + nameMapLookup = new Dictionary(); + } + + /// + /// Replaces a value in the name map at a particular index. + /// + /// The index to overwrite in the name map. + /// The value that will be replaced in the name map. + public void SetNameReference(int index, FString value) + { + FixNameMapLookupIfNeeded(); + nameMapIndexList[index] = value; + nameMapLookup[value.Value] = index; + } + + /// + /// Gets a value in the name map at a particular index. + /// + /// The index to return the value at. + /// The value at the index provided. + public FString GetNameReference(int index) + { + FixNameMapLookupIfNeeded(); + if (index < 0) return new FString(Convert.ToString(-index)); + if (index >= nameMapIndexList.Count) return new FString(Convert.ToString(index)); + return nameMapIndexList[index]; + } + + /// + /// Gets a value in the name map at a particular index, but with the index zero being treated as if it is not valid. + /// + /// The index to return the value at. + /// The value at the index provided. + public FString GetNameReferenceWithoutZero(int index) + { + FixNameMapLookupIfNeeded(); + if (index <= 0) return new FString(Convert.ToString(-index)); + if (index >= nameMapIndexList.Count) return new FString(Convert.ToString(index)); + return nameMapIndexList[index]; + } + + /// + /// Checks whether or not the value exists in the name map. + /// + /// The value to search the name map for. + /// true if the value appears in the name map, otherwise false. + public bool ContainsNameReference(FString search) + { + FixNameMapLookupIfNeeded(); + return nameMapLookup.ContainsKey(search.Value); + } + + /// + /// Searches the name map for a particular value. + /// + /// The value to search the name map for. + /// The index at which the value appears in the name map. + /// Thrown when the value provided does not appear in the name map. + public int SearchNameReference(FString search) + { + FixNameMapLookupIfNeeded(); + if (ContainsNameReference(search)) return nameMapLookup[search.Value]; + throw new NameMapOutOfRangeException(search); + } + + /// + /// Adds a new value to the name map. + /// + /// The value to add to the name map. + /// Whether or not to add a new entry if the value provided already exists in the name map. + /// The index of the new value in the name map. If the value already existed in the name map beforehand, that index will be returned instead. + /// Thrown when forceAddDuplicates is false and the value provided is null or empty. + public int AddNameReference(FString name, bool forceAddDuplicates = false) + { + FixNameMapLookupIfNeeded(); + + if (!forceAddDuplicates) + { + if (name?.Value == null) throw new ArgumentException("Cannot add a null FString to the name map"); + if (name.Value == string.Empty) throw new ArgumentException("Cannot add an empty FString to the name map"); + if (ContainsNameReference(name)) return SearchNameReference(name); + } + + if (isSerializationTime) throw new InvalidOperationException("Attempt to add name \"" + name + "\" to name map during serialization time"); + nameMapIndexList.Add(name); + nameMapLookup[name.Value] = nameMapIndexList.Count - 1; + return nameMapIndexList.Count - 1; + } + + /// + /// Adds a new import to the import map. This is equivalent to adding directly to the list. + /// + /// The new import to add to the import map. + /// The FPackageIndex corresponding to the newly-added import. + public FPackageIndex AddImport(Import li) + { + Imports.Add(li); + return FPackageIndex.FromImport(Imports.Count - 1); + } + + /// + /// Searches for and returns this asset's ClassExport, if one exists. + /// + /// The asset's ClassExport if one exists, otherwise null. + public ClassExport GetClassExport() + { + foreach (Export cat in Exports) + { + if (cat is ClassExport bgcCat) return bgcCat; + } + return null; + } + + /// + /// Finds the class path and export name of the SuperStruct of this asset, if it exists. + /// + /// The class path of the SuperStruct of this asset, if it exists. + /// The export name of the SuperStruct of this asset, if it exists. + public void GetParentClass(out FName parentClassPath, out FName parentClassExportName) + { + parentClassPath = null; + parentClassExportName = null; + + var bgcCat = GetClassExport(); + if (bgcCat == null) return; + + Import parentClassLink = bgcCat.SuperStruct.ToImport(this); + if (parentClassLink == null) return; + if (parentClassLink.OuterIndex.Index >= 0) return; + + parentClassExportName = parentClassLink.ObjectName; + parentClassPath = parentClassLink.OuterIndex.ToImport(this).ObjectName; + } + + /// + /// Fetches the version of a custom version in this asset. + /// + /// The GUID of the custom version to retrieve. + /// The version of the retrieved custom version. + public int GetCustomVersion(Guid key) + { + for (int i = 0; i < CustomVersionContainer.Count; i++) + { + CustomVersion custVer = CustomVersionContainer[i]; + if (custVer.Key == key) + { + return custVer.Version; + } + } + + return -1; // https://github.com/EpicGames/UnrealEngine/blob/99b6e203a15d04fc7bbbf554c421a985c1ccb8f1/Engine/Source/Runtime/Core/Private/Serialization/Archive.cpp#L578 + } + + /// + /// Fetches the version of a custom version in this asset. + /// + /// The friendly name of the custom version to retrieve. + /// The version of the retrieved custom version. + public int GetCustomVersion(string friendlyName) + { + for (int i = 0; i < CustomVersionContainer.Count; i++) + { + CustomVersion custVer = CustomVersionContainer[i]; + if (custVer.FriendlyName == friendlyName) + { + return custVer.Version; + } + } + + return -1; + } + + /// + /// Fetches a custom version's enum value based off of its type. + /// + /// The enum type of the custom version to retrieve. + /// The enum value of the requested custom version. + /// Thrown when T is not an enumerated type. + public T GetCustomVersion() + { + Type customVersionEnumType = typeof(T); + if (!customVersionEnumType.IsEnum) throw new ArgumentException("T must be an enumerated type"); + + for (int i = 0; i < CustomVersionContainer.Count; i++) + { + CustomVersion custVer = CustomVersionContainer[i]; + if (custVer.FriendlyName == customVersionEnumType.Name) + { + return (T)(object)custVer.Version; + } + } + + // Try and guess the custom version based off the engine version + T[] allVals = (T[])Enum.GetValues(customVersionEnumType); + for (int i = allVals.Length - 1; i >= 0; i--) + { + T val = allVals[i]; + var attributes = customVersionEnumType.GetMember(val.ToString())?[0]?.GetCustomAttributes(typeof(IntroducedAttribute), false); + if (attributes == null || attributes.Length <= 0) continue; + if (EngineVersion >= ((IntroducedAttribute)attributes[0]).IntroducedVersion) return val; + } + + return (T)(object)-1; + } + + private static int GuessCustomVersionFromTypeAndEngineVersion(UE4Version chosenVersion, Type typ) + { + string[] allVals = Enum.GetNames(typ); + for (int i = allVals.Length - 1; i >= 0; i--) + { + string val = allVals[i]; + var attributes = typ.GetMember(val)?[0]?.GetCustomAttributes(typeof(IntroducedAttribute), false); + if (attributes == null || attributes.Length <= 0) continue; + if (chosenVersion >= ((IntroducedAttribute)attributes[0]).IntroducedVersion) return i; + } + return -1; + } + + /// + /// Fetches a list of all default custom versions for a specific Unreal version. + /// + /// The version of the engine to check against. + /// A list of all the default custom version values for the given engine version. + public static List GetDefaultCustomVersionContainer(UE4Version chosenVersion) + { + List res = new List(); + foreach (KeyValuePair entry in CustomVersion.GuidToCustomVersionStringMap) + { + Type customVersionType = Type.GetType("UAssetAPI." + entry.Value); + if (customVersionType == null) continue; + int guessedCustomVersion = GuessCustomVersionFromTypeAndEngineVersion(chosenVersion, customVersionType); + if (guessedCustomVersion < 0) continue; + res.Add(new CustomVersion(entry.Key, guessedCustomVersion)); + } + return res; + } + + /// + /// Searches for an import in the import map based off of certain parameters. + /// + /// The ClassPackage that the requested import will have. + /// The ClassName that the requested import will have. + /// The CuterIndex that the requested import will have. + /// The ObjectName that the requested import will have. + /// The index of the requested import in the name map, or zero if one could not be found. + public int SearchForImport(FName classPackage, FName className, FPackageIndex outerIndex, FName objectName) + { + int currentPos = 0; + for (int i = 0; i < Imports.Count; i++) + { + currentPos--; + if (classPackage == Imports[i].ClassPackage + && className == Imports[i].ClassName + && outerIndex == Imports[i].OuterIndex + && objectName == Imports[i].ObjectName) + { + return currentPos; + } + + } + + return 0; + } + + /// + /// Searches for an import in the import map based off of certain parameters. + /// + /// The ClassPackage that the requested import will have. + /// The ClassName that the requested import will have. + /// The ObjectName that the requested import will have. + /// The index of the requested import in the name map, or zero if one could not be found. + public int SearchForImport(FName classPackage, FName className, FName objectName) + { + int currentPos = 0; + for (int i = 0; i < Imports.Count; i++) + { + currentPos--; + if (classPackage == Imports[i].ClassPackage + && className == Imports[i].ClassName + && objectName == Imports[i].ObjectName) + { + return currentPos; + } + + } + + return 0; + } + + /// + /// Searches for an import in the import map based off of certain parameters. + /// + /// The ObjectName that the requested import will have. + /// The index of the requested import in the name map, or zero if one could not be found. + public int SearchForImport(FName objectName) + { + int currentPos = 0; + for (int i = 0; i < Imports.Count; i++) + { + currentPos--; + if (objectName == Imports[i].ObjectName) return currentPos; + } + + return 0; + } + + /// + /// The package file version number when this package was saved. + /// + /// + /// The lower 16 bits stores the UE3 engine version, while the upper 16 bits stores the UE4/licensee version. For newer packages this is -7. + /// + /// + /// Version + /// Description + /// + /// + /// -2 + /// indicates presence of enum-based custom versions + /// + /// + /// -3 + /// indicates guid-based custom versions + /// + /// + /// -4 + /// indicates removal of the UE3 version. Packages saved with this ID cannot be loaded in older engine versions + /// + /// + /// -5 + /// indicates the replacement of writing out the "UE3 version" so older versions of engine can gracefully fail to open newer packages + /// + /// + /// -6 + /// indicates optimizations to how custom versions are being serialized + /// + /// + /// -7 + /// indicates the texture allocation info has been removed from the summary + /// + /// + /// + public int LegacyFileVersion; + + /// + /// Should this asset not serialize its engine and custom versions? + /// + public bool IsUnversioned; + + /// + /// The licensee file version. Used by some games to add their own Engine-level versioning. + /// + public int FileVersionLicenseeUE4; + + /// + /// All the custom versions stored in the archive. + /// + public List CustomVersionContainer = null; + + /// + /// Map of object imports. UAssetAPI used to call these "links." + /// + public List Imports; + + /// + /// Map of object exports. UAssetAPI used to call these "categories." + /// + public List Exports; + + /// + /// List of dependency lists for each export. + /// + public List DependsMap; + + /// + /// List of packages that are soft referenced by this package. + /// + public List SoftPackageReferenceList; + + /// + /// Uncertain + /// + public List AssetRegistryData; + + /// + /// Tile information used by WorldComposition. + /// Defines properties necessary for tile positioning in the world. + /// + public FWorldTileInfo WorldTileInfo; + + /// + /// Data about previous versions of this package. + /// + public List Generations; + + /// + /// Current ID for this package. Effectively unused. + /// + public Guid PackageGuid; + + /// + /// Engine version this package was saved with. This may differ from CompatibleWithEngineVersion for assets saved with a hotfix release. + /// + public FEngineVersion RecordedEngineVersion; + + /// + /// Engine version this package is compatible with. Assets saved by Hotfix releases and engine versions that maintain binary compatibility will have + /// a CompatibleWithEngineVersion.Patch that matches the original release (as opposed to SavedByEngineVersion which will have a patch version of the new release). + /// + public FEngineVersion RecordedCompatibleWithEngineVersion; + + /// + /// Streaming install ChunkIDs + /// + public int[] ChunkIDs; + + /// + /// The flags for this package. + /// + [JsonConverter(typeof(StringEnumConverter))] + public EPackageFlags PackageFlags; + + /// + /// Value that is used by the Unreal Engine to determine if the package was saved by Epic, a licensee, modder, etc. + /// + public uint PackageSource; + + /// + /// The Generic Browser folder name that this package lives in. Usually "None" in cooked assets. + /// + public FString FolderName; + + /// + /// In MapProperties that have StructProperties as their keys or values, there is no universal, context-free way to determine the type of the struct. To that end, this dictionary maps MapProperty names to the type of the structs within them (tuple of key struct type and value struct type) if they are not None-terminated property lists. + /// + [JsonIgnore] + public Dictionary> MapStructTypeOverride = new Dictionary>() + { + { "ColorDatabase", new Tuple(null, new FString("LinearColor")) }, + { "PlayerCharacterIDs", new Tuple(new FString("Guid"), null) } + }; + + /// + /// External programs often improperly specify name map hashes, so in this map we can preserve those changes to avoid confusion. + /// + [JsonIgnore] + public Dictionary OverrideNameMapHashes; + + /// This is called "TotalHeaderSize" in UE4 where header refers to the whole summary, whereas in UAssetAPI "header" refers to just the data before the start of the name map + internal int SectionSixOffset = 0; + + /// Number of names used in this package + internal int NameCount = 0; + + /// Location into the file on disk for the name data + internal int NameOffset; + + /// Number of gatherable text data items in this package + [JsonProperty] + internal int GatherableTextDataCount; + + /// Location into the file on disk for the gatherable text data items + [JsonProperty] + internal int GatherableTextDataOffset; + + /// Number of exports contained in this package + internal int ExportCount = 0; + + /// Location into the file on disk for the "Export Details" data + internal int ExportOffset = 0; + + /// Number of imports contained in this package + internal int ImportCount = 0; + + /// Location into the file on disk for the ImportMap data + internal int ImportOffset = 0; + + /// Location into the file on disk for the DependsMap data + internal int DependsOffset = 0; + + /// Number of soft package references contained in this package + internal int SoftPackageReferencesCount = 0; + + /// Location into the file on disk for the soft package reference list + internal int SoftPackageReferencesOffset = 0; + + /// Location into the file on disk for the SearchableNamesMap data + [JsonProperty] + internal int SearchableNamesOffset; + + /// Thumbnail table offset + [JsonProperty] + internal int ThumbnailTableOffset; + + /// Should be zero + [JsonProperty] + internal uint CompressionFlags; + + /// Location into the file on disk for the asset registry tag data + internal int AssetRegistryDataOffset; + + /// Offset to the location in the file where the bulkdata starts + internal long BulkDataStartOffset; + + /// Offset to the location in the file where the FWorldTileInfo data start + internal int WorldTileInfoDataOffset; + + /// Number of preload dependencies contained in this package + internal int PreloadDependencyCount; + + /// Location into the file on disk for the preload dependency data + internal int PreloadDependencyOffset; + + [JsonProperty] + internal bool doWeHaveDependsMap = true; + [JsonProperty] + internal bool doWeHaveSoftPackageReferences = true; + [JsonProperty] + internal bool doWeHaveAssetRegistryData = true; + [JsonProperty] + internal bool doWeHaveWorldTileInfo = true; + [JsonIgnore] + internal bool isSerializationTime = false; + + /// + /// Internal list of name map entries. Do not directly add values to here under any circumstances; use instead + /// + [JsonProperty("NameMap", Order = -2)] + private List nameMapIndexList; + + /// + /// Internal lookup for name map entries. Do not directly add values to here under any circumstances; use instead + /// + private Dictionary nameMapLookup = new Dictionary(); + + /// + /// Copies a portion of a stream to another stream. + /// + /// The input stream. + /// The output stream. + /// The offset in the input stream to start copying from. + /// The length in bytes of the data to be copied. + private static void CopySplitUp(Stream input, Stream output, int start, int leng) + { + input.Seek(start, SeekOrigin.Begin); + output.Seek(0, SeekOrigin.Begin); + + byte[] buffer = new byte[32768]; + int read; + while (leng > 0 && (read = input.Read(buffer, 0, Math.Min(buffer.Length, leng))) > 0) + { + output.Write(buffer, 0, read); + leng -= read; + } + } + + /// + /// Magic number for the .uasset format + /// + public static readonly uint UASSET_MAGIC = 0x9E2A83C1; + + /// + /// Magic number for Ace Combat 7 encrypted .uasset format + /// + public static readonly uint ACE7_MAGIC = 0x37454341; + + /// + /// Reads the initial portion of the asset (everything before the name map). + /// + /// + /// Thrown when this is an unversioned asset and is unspecified. + /// Throw when the asset cannot be parsed correctly. + private void ReadHeader(AssetBinaryReader reader) + { + reader.BaseStream.Seek(0, SeekOrigin.Begin); + uint fileSignature = reader.ReadUInt32(); + if (fileSignature != UASSET_MAGIC) throw new FormatException("File signature mismatch"); + + LegacyFileVersion = reader.ReadInt32(); + if (LegacyFileVersion != -4) + { + reader.ReadInt32(); // LegacyUE3Version for backwards-compatibility with UE3 games: always 864 in versioned assets, always 0 in unversioned assets + } + + UE4Version fileVersionUE4 = (UE4Version)reader.ReadInt32(); + if (fileVersionUE4 > UE4Version.UNKNOWN) + { + IsUnversioned = false; + EngineVersion = fileVersionUE4; + } + else + { + IsUnversioned = true; + if (EngineVersion == UE4Version.UNKNOWN) throw new UnknownEngineVersionException("Cannot begin serialization of an unversioned asset before an engine version is manually specified"); + } + + FileVersionLicenseeUE4 = reader.ReadInt32(); + + // Custom versions container + int numCustomVersions = 0; + if (LegacyFileVersion <= -2) + { + // TODO: support for enum-based custom versions + if (CustomVersionContainer == null) CustomVersionContainer = new List(); + + numCustomVersions = reader.ReadInt32(); + for (int i = 0; i < numCustomVersions; i++) + { + var customVersionID = new Guid(reader.ReadBytes(16)); + var customVersionNumber = reader.ReadInt32(); + CustomVersionContainer.Add(new CustomVersion(customVersionID, customVersionNumber)); + } + } + + SectionSixOffset = reader.ReadInt32(); // 24 + FolderName = reader.ReadFString(); + PackageFlags = (EPackageFlags)reader.ReadUInt32(); + NameCount = reader.ReadInt32(); + NameOffset = reader.ReadInt32(); + if (EngineVersion >= UE4Version.VER_UE4_SERIALIZE_TEXT_IN_PACKAGES) + { + GatherableTextDataCount = reader.ReadInt32(); + GatherableTextDataOffset = reader.ReadInt32(); + } + + ExportCount = reader.ReadInt32(); + ExportOffset = reader.ReadInt32(); // 61 + ImportCount = reader.ReadInt32(); // 65 + ImportOffset = reader.ReadInt32(); // 69 (haha funny) + DependsOffset = reader.ReadInt32(); // 73 + if (EngineVersion >= UE4Version.VER_UE4_ADD_STRING_ASSET_REFERENCES_MAP) + { + SoftPackageReferencesCount = reader.ReadInt32(); // 77 + SoftPackageReferencesOffset = reader.ReadInt32(); // 81 + } + if (EngineVersion >= UE4Version.VER_UE4_ADDED_SEARCHABLE_NAMES) + { + SearchableNamesOffset = reader.ReadInt32(); + } + ThumbnailTableOffset = reader.ReadInt32(); + + PackageGuid = new Guid(reader.ReadBytes(16)); + + Generations = new List(); + int generationCount = reader.ReadInt32(); + for (int i = 0; i < generationCount; i++) + { + int genNumExports = reader.ReadInt32(); + int genNumNames = reader.ReadInt32(); + Generations.Add(new FGenerationInfo(genNumExports, genNumNames)); + } + + if (EngineVersion >= UE4Version.VER_UE4_ENGINE_VERSION_OBJECT) + { + RecordedEngineVersion = new FEngineVersion(reader); + } + else + { + RecordedEngineVersion = new FEngineVersion(4, 0, 0, reader.ReadUInt32(), FString.FromString("")); + } + + if (EngineVersion >= UE4Version.VER_UE4_PACKAGE_SUMMARY_HAS_COMPATIBLE_ENGINE_VERSION) + { + RecordedCompatibleWithEngineVersion = new FEngineVersion(reader); + } + else + { + RecordedCompatibleWithEngineVersion = RecordedEngineVersion; + } + + CompressionFlags = reader.ReadUInt32(); + int numCompressedChunks = reader.ReadInt32(); + if (numCompressedChunks > 0) throw new FormatException("Asset has package-level compression and is likely too old to be parsed"); + + PackageSource = reader.ReadUInt32(); + + int numAdditionalPackagesToCook = reader.ReadInt32(); // unused + if (numAdditionalPackagesToCook > 0) throw new FormatException("Asset has AdditionalPackagesToCook and is likely too old to be parsed"); + + if (LegacyFileVersion > -7) + { + int numTextureAllocations = reader.ReadInt32(); // unused + if (numTextureAllocations > 0) throw new FormatException("Asset has texture allocation info and is likely too old to be parsed"); + } + + AssetRegistryDataOffset = reader.ReadInt32(); + BulkDataStartOffset = reader.ReadInt64(); + + if (EngineVersion >= UE4Version.VER_UE4_WORLD_LEVEL_INFO) + { + WorldTileInfoDataOffset = reader.ReadInt32(); + } + + if (EngineVersion >= UE4Version.VER_UE4_CHANGED_CHUNKID_TO_BE_AN_ARRAY_OF_CHUNKIDS) + { + int numChunkIDs = reader.ReadInt32(); + ChunkIDs = new int[numChunkIDs]; + for (int i = 0; i < numChunkIDs; i++) + { + ChunkIDs[i] = reader.ReadInt32(); + } + } + else if (EngineVersion >= UE4Version.VER_UE4_ADDED_CHUNKID_TO_ASSETDATA_AND_UPACKAGE) + { + ChunkIDs = new int[1]; + ChunkIDs[0] = reader.ReadInt32(); + } + + if (EngineVersion >= UE4Version.VER_UE4_PRELOAD_DEPENDENCIES_IN_COOKED_EXPORTS) + { + PreloadDependencyCount = reader.ReadInt32(); + PreloadDependencyOffset = reader.ReadInt32(); + } + } + + /// + /// Reads an asset into memory. + /// + /// The input reader. + /// An array of export indexes to skip parsing. For most applications, this should be left blank. + /// An array of export indexes that must be read, overriding entries in the manualSkips parameter. For most applications, this should be left blank. + /// Thrown when this is an unversioned asset and is unspecified. + /// Throw when the asset cannot be parsed correctly. + public void Read(AssetBinaryReader reader, int[] manualSkips = null, int[] forceReads = null) + { + // Header + ReadHeader(reader); + + // Name map + reader.BaseStream.Seek(NameOffset, SeekOrigin.Begin); + + OverrideNameMapHashes = new Dictionary(); + ClearNameIndexList(); + for (int i = 0; i < NameCount; i++) + { + FString nameInMap = reader.ReadNameMapString(out uint hashes); + if (hashes == 0) OverrideNameMapHashes[nameInMap] = 0; + AddNameReference(nameInMap, true); + } + + // Imports + Imports = new List(); + if (ImportOffset > 0) + { + reader.BaseStream.Seek(ImportOffset, SeekOrigin.Begin); + for (int i = 0; i < ImportCount; i++) + { + Imports.Add(new Import(reader.ReadFName(), reader.ReadFName(), new FPackageIndex(reader.ReadInt32()), reader.ReadFName())); + } + } + + // Export details + Exports = new List(); + if (ExportOffset > 0) + { + reader.BaseStream.Seek(ExportOffset, SeekOrigin.Begin); + for (int i = 0; i < ExportCount; i++) + { + var newExport = new Export(this, new byte[0]); + newExport.ClassIndex = new FPackageIndex(reader.ReadInt32()); + newExport.SuperIndex = new FPackageIndex(reader.ReadInt32()); + if (EngineVersion >= UE4Version.VER_UE4_TemplateIndex_IN_COOKED_EXPORTS) + { + newExport.TemplateIndex = new FPackageIndex(reader.ReadInt32()); + } + newExport.OuterIndex = new FPackageIndex(reader.ReadInt32()); + newExport.ObjectName = reader.ReadFName(); + newExport.ObjectFlags = (EObjectFlags)reader.ReadUInt32(); + if (EngineVersion < UE4Version.VER_UE4_64BIT_EXPORTMAP_SERIALSIZES) + { + newExport.SerialSize = reader.ReadInt32(); + newExport.SerialOffset = reader.ReadInt32(); + } + else + { + newExport.SerialSize = reader.ReadInt64(); + newExport.SerialOffset = reader.ReadInt64(); + } + newExport.bForcedExport = reader.ReadInt32() == 1; + newExport.bNotForClient = reader.ReadInt32() == 1; + newExport.bNotForServer = reader.ReadInt32() == 1; + newExport.PackageGuid = new Guid(reader.ReadBytes(16)); + newExport.PackageFlags = (EPackageFlags)reader.ReadUInt32(); + if (EngineVersion >= UE4Version.VER_UE4_LOAD_FOR_EDITOR_GAME) + { + newExport.bNotAlwaysLoadedForEditorGame = reader.ReadInt32() == 1; + } + if (EngineVersion >= UE4Version.VER_UE4_COOKED_ASSETS_IN_EDITOR_SUPPORT) + { + newExport.bIsAsset = reader.ReadInt32() == 1; + } + if (EngineVersion >= UE4Version.VER_UE4_PRELOAD_DEPENDENCIES_IN_COOKED_EXPORTS) + { + newExport.FirstExportDependencyOffset = reader.ReadInt32(); + newExport.SerializationBeforeSerializationDependenciesSize = reader.ReadInt32(); + newExport.CreateBeforeSerializationDependenciesSize = reader.ReadInt32(); + newExport.SerializationBeforeCreateDependenciesSize = reader.ReadInt32(); + newExport.CreateBeforeCreateDependenciesSize = reader.ReadInt32(); + } + + Exports.Add(newExport); + } + } + + // DependsMap + DependsMap = new List(); + if (DependsOffset > 0) + { + reader.BaseStream.Seek(DependsOffset, SeekOrigin.Begin); + for (int i = 0; i < ExportCount; i++) + { + int size = reader.ReadInt32(); + int[] data = new int[size]; + for (int j = 0; j < size; j++) + { + data[j] = reader.ReadInt32(); + } + DependsMap.Add(data); + } + } + else + { + doWeHaveDependsMap = false; + } + + // SoftPackageReferenceList + SoftPackageReferenceList = new List(); + if (SoftPackageReferencesOffset > 0) + { + reader.BaseStream.Seek(SoftPackageReferencesOffset, SeekOrigin.Begin); + for (int i = 0; i < SoftPackageReferencesCount; i++) + { + SoftPackageReferenceList.Add(reader.ReadFString()); + } + } + else + { + doWeHaveSoftPackageReferences = false; + } + + // AssetRegistryData + AssetRegistryData = new List(); + if (AssetRegistryDataOffset > 0) + { + reader.BaseStream.Seek(AssetRegistryDataOffset, SeekOrigin.Begin); + int numAssets = reader.ReadInt32(); +#pragma warning disable CS0162 // Unreachable code detected + for (int i = 0; i < numAssets; i++) + { + throw new NotImplementedException("Asset registry data is not yet supported. Please let me know if you see this error message"); + } +#pragma warning restore CS0162 // Unreachable code detected + } + else + { + doWeHaveAssetRegistryData = false; + } + + // WorldTileInfoDataOffset + WorldTileInfo = null; + if (WorldTileInfoDataOffset > 0) + { + //reader.BaseStream.Seek(WorldTileInfoDataOffset, SeekOrigin.Begin); + WorldTileInfo = new FWorldTileInfo(); + WorldTileInfo.Read(reader, this); + } + else + { + doWeHaveWorldTileInfo = false; + } + + // PreloadDependencies + if (this.UseSeparateBulkDataFiles) + { + for (int i = 0; i < Exports.Count; i++) + { + reader.BaseStream.Seek(PreloadDependencyOffset, SeekOrigin.Begin); + reader.BaseStream.Seek(Exports[i].FirstExportDependencyOffset * sizeof(int), SeekOrigin.Current); + + Exports[i].SerializationBeforeSerializationDependencies = new List(Exports[i].SerializationBeforeSerializationDependenciesSize); + for (int j = 0; j < Exports[i].SerializationBeforeSerializationDependenciesSize; j++) Exports[i].SerializationBeforeSerializationDependencies.Add(FPackageIndex.FromRawIndex(reader.ReadInt32())); + + Exports[i].CreateBeforeSerializationDependencies = new List(Exports[i].CreateBeforeSerializationDependenciesSize); + for (int j = 0; j < Exports[i].CreateBeforeSerializationDependenciesSize; j++) Exports[i].CreateBeforeSerializationDependencies.Add(FPackageIndex.FromRawIndex(reader.ReadInt32())); + + Exports[i].SerializationBeforeCreateDependencies = new List(Exports[i].SerializationBeforeCreateDependenciesSize); + for (int j = 0; j < Exports[i].SerializationBeforeCreateDependenciesSize; j++) Exports[i].SerializationBeforeCreateDependencies.Add(FPackageIndex.FromRawIndex(reader.ReadInt32())); + + Exports[i].CreateBeforeCreateDependencies = new List(Exports[i].CreateBeforeCreateDependenciesSize); + for (int j = 0; j < Exports[i].CreateBeforeCreateDependenciesSize; j++) Exports[i].CreateBeforeCreateDependencies.Add(FPackageIndex.FromRawIndex(reader.ReadInt32())); + } + } + + // Export data + if (SectionSixOffset > 0 && Exports.Count > 0) + { + for (int i = 0; i < Exports.Count; i++) + { + reader.BaseStream.Seek(Exports[i].SerialOffset, SeekOrigin.Begin); + if (manualSkips != null && manualSkips.Contains(i)) + { + if (forceReads == null || !forceReads.Contains(i)) + { + Exports[i] = Exports[i].ConvertToChildExport(); + ((RawExport)Exports[i]).Data = reader.ReadBytes((int)Exports[i].SerialSize); + continue; + } + } + + try + { + long nextStarting = reader.BaseStream.Length - 4; + if ((Exports.Count - 1) > i) nextStarting = Exports[i + 1].SerialOffset; + + FName exportClassTypeName = Exports[i].GetExportClassType(); + string exportClassType = exportClassTypeName.Value.Value; + switch (exportClassType) + { + case "Level": + Exports[i] = Exports[i].ConvertToChildExport(); + Exports[i].Read(reader, (int)nextStarting); + break; + case "StringTable": + Exports[i] = Exports[i].ConvertToChildExport(); + Exports[i].Read(reader, (int)nextStarting); + break; + case "Enum": + case "UserDefinedEnum": + Exports[i] = Exports[i].ConvertToChildExport(); + Exports[i].Read(reader, (int)nextStarting); + break; + case "Function": + Exports[i] = Exports[i].ConvertToChildExport(); + Exports[i].Read(reader, (int)nextStarting); + break; + default: + if (exportClassType.EndsWith("DataTable")) + { + Exports[i] = Exports[i].ConvertToChildExport(); + Exports[i].Read(reader, (int)nextStarting); + } + else if (exportClassType.EndsWith("BlueprintGeneratedClass")) + { + var bgc = Exports[i].ConvertToChildExport(); + Exports[i] = bgc; + Exports[i].Read(reader, (int)nextStarting); + + // Check to see if we can add some new map type overrides + if (bgc.LoadedProperties != null) + { + foreach (FProperty entry in bgc.LoadedProperties) + { + if (entry is FMapProperty fMapEntry) + { + FName keyOverride = null; + FName valueOverride = null; + if (fMapEntry.KeyProp is FStructProperty keyPropStruc && keyPropStruc.Struct.IsImport()) keyOverride = keyPropStruc.Struct.ToImport(this).ObjectName; + if (fMapEntry.ValueProp is FStructProperty valuePropStruc && valuePropStruc.Struct.IsImport()) valueOverride = valuePropStruc.Struct.ToImport(this).ObjectName; + + this.MapStructTypeOverride.Add(fMapEntry.Name.Value.Value, new Tuple(keyOverride.Value, valueOverride.Value)); + } + } + } + } + else if (MainSerializer.PropertyTypeRegistry.ContainsKey(exportClassType)) + { + Exports[i] = Exports[i].ConvertToChildExport(); + Exports[i].Read(reader, (int)nextStarting); + } + else + { + Exports[i] = Exports[i].ConvertToChildExport(); + Exports[i].Read(reader, (int)nextStarting); + } + break; + } + + long extrasLen = nextStarting - reader.BaseStream.Position; + if (extrasLen < 0) + { + throw new FormatException("Invalid padding at end of export " + (i + 1) + ": " + extrasLen + " bytes"); + } + else + { + Exports[i].Extras = reader.ReadBytes((int)extrasLen); + } + } + catch (Exception ex) + { +#if DEBUG + Debug.WriteLine("\nFailed to parse export " + (i + 1) + ": " + ex.ToString()); +#endif + reader.BaseStream.Seek(Exports[i].SerialOffset, SeekOrigin.Begin); + Exports[i] = Exports[i].ConvertToChildExport(); + ((RawExport)Exports[i]).Data = reader.ReadBytes((int)Exports[i].SerialSize); + } + } + } + } + + /// + /// Serializes the initial portion of the asset from memory. + /// + /// A byte array which represents the serialized binary data of the initial portion of the asset. + private byte[] MakeHeader() + { + var stre = new MemoryStream(this.NameOffset); + AssetBinaryWriter writer = new AssetBinaryWriter(stre, this); + + writer.Write(UAsset.UASSET_MAGIC); + writer.Write(LegacyFileVersion); + if (LegacyFileVersion != 4) + { + writer.Write(IsUnversioned ? 0 : 864); + } + + if (IsUnversioned) + { + writer.Write(0); + } + else + { + writer.Write((int)EngineVersion); + } + + writer.Write(FileVersionLicenseeUE4); + if (LegacyFileVersion <= -2) + { + if (IsUnversioned) + { + writer.Write(0); + } + else + { + // TODO: support for enum-based custom versions + writer.Write(CustomVersionContainer.Count); + for (int i = 0; i < CustomVersionContainer.Count; i++) + { + writer.Write(CustomVersionContainer[i].Key.ToByteArray()); + writer.Write(CustomVersionContainer[i].Version); + } + } + } + + writer.Write(SectionSixOffset); + writer.Write(FolderName); + writer.Write((uint)PackageFlags); + writer.Write(NameCount); + writer.Write(NameOffset); + if (EngineVersion >= UE4Version.VER_UE4_SERIALIZE_TEXT_IN_PACKAGES) + { + writer.Write(GatherableTextDataCount); + writer.Write(GatherableTextDataOffset); + } + writer.Write(ExportCount); + writer.Write(ExportOffset); // 61 + writer.Write(ImportCount); // 65 + writer.Write(ImportOffset); // 69 (haha funny) + writer.Write(DependsOffset); // 73 + if (EngineVersion >= UE4Version.VER_UE4_ADD_STRING_ASSET_REFERENCES_MAP) + { + writer.Write(SoftPackageReferencesCount); // 77 + writer.Write(SoftPackageReferencesOffset); // 81 + } + if (EngineVersion >= UE4Version.VER_UE4_ADDED_SEARCHABLE_NAMES) + { + writer.Write(SearchableNamesOffset); + } + writer.Write(ThumbnailTableOffset); + + writer.Write(PackageGuid.ToByteArray()); + writer.Write(Generations.Count); + for (int i = 0; i < Generations.Count; i++) + { + Generations[i].ExportCount = ExportCount; + Generations[i].NameCount = NameCount; + writer.Write(Generations[i].ExportCount); + writer.Write(Generations[i].NameCount); + } + + if (EngineVersion >= UE4Version.VER_UE4_ENGINE_VERSION_OBJECT) + { + RecordedEngineVersion.Write(writer); + } + else + { + writer.Write(RecordedEngineVersion.Changelist); + } + + if (EngineVersion >= UE4Version.VER_UE4_PACKAGE_SUMMARY_HAS_COMPATIBLE_ENGINE_VERSION) + { + RecordedCompatibleWithEngineVersion.Write(writer); + } + + writer.Write(CompressionFlags); + writer.Write((int)0); // numCompressedChunks + writer.Write(PackageSource); + writer.Write((int)0); // numAdditionalPackagesToCook + + if (LegacyFileVersion > -7) + { + writer.Write((int)0); // numTextureAllocations + } + + writer.Write(AssetRegistryDataOffset); + writer.Write(BulkDataStartOffset); + + if (EngineVersion >= UE4Version.VER_UE4_WORLD_LEVEL_INFO) + { + writer.Write(WorldTileInfoDataOffset); + } + + if (EngineVersion >= UE4Version.VER_UE4_CHANGED_CHUNKID_TO_BE_AN_ARRAY_OF_CHUNKIDS) + { + writer.Write(ChunkIDs.Length); + for (int i = 0; i < ChunkIDs.Length; i++) + { + writer.Write(ChunkIDs[i]); + } + } + else if (EngineVersion >= UE4Version.VER_UE4_ADDED_CHUNKID_TO_ASSETDATA_AND_UPACKAGE) + { + writer.Write(ChunkIDs[0]); + } + + if (EngineVersion >= UE4Version.VER_UE4_PRELOAD_DEPENDENCIES_IN_COOKED_EXPORTS) + { + writer.Write(PreloadDependencyCount); + writer.Write(PreloadDependencyOffset); + } + + return stre.ToArray(); + } + + /// + /// Serializes an asset from memory. + /// + /// A stream that the asset has been serialized to. + public MemoryStream WriteData() + { + isSerializationTime = true; + var stre = new MemoryStream(); + try + { + AssetBinaryWriter writer = new AssetBinaryWriter(stre, this); + + // Header + writer.Seek(0, SeekOrigin.Begin); + writer.Write(MakeHeader()); + + // Name map + this.NameOffset = (int)writer.BaseStream.Position; + this.NameCount = this.nameMapIndexList.Count; + for (int i = 0; i < this.nameMapIndexList.Count; i++) + { + writer.Write(nameMapIndexList[i]); + + if (EngineVersion >= UE4Version.VER_UE4_NAME_HASHES_SERIALIZED) + { + if (OverrideNameMapHashes != null && OverrideNameMapHashes.ContainsKey(nameMapIndexList[i])) + { + writer.Write(OverrideNameMapHashes[nameMapIndexList[i]]); + } + else + { + writer.Write(CRCGenerator.GenerateHash(nameMapIndexList[i])); + } + } + } + + // Imports + if (this.Imports.Count > 0) + { + this.ImportOffset = (int)writer.BaseStream.Position; + this.ImportCount = this.Imports.Count; + for (int i = 0; i < this.Imports.Count; i++) + { + writer.Write(this.Imports[i].ClassPackage); + writer.Write(this.Imports[i].ClassName); + writer.Write(this.Imports[i].OuterIndex.Index); + writer.Write(this.Imports[i].ObjectName); + } + } + else + { + this.ImportOffset = 0; + } + + // Export details + if (this.Exports.Count > 0) + { + this.ExportOffset = (int)writer.BaseStream.Position; + this.ExportCount = this.Exports.Count; + for (int i = 0; i < this.Exports.Count; i++) + { + Export us = this.Exports[i]; + writer.Write(us.ClassIndex.Index); + writer.Write(us.SuperIndex.Index); + if (EngineVersion >= UE4Version.VER_UE4_TemplateIndex_IN_COOKED_EXPORTS) + { + writer.Write(us.TemplateIndex.Index); + } + writer.Write(us.OuterIndex.Index); + writer.Write(us.ObjectName); + writer.Write((uint)us.ObjectFlags); + if (EngineVersion < UE4Version.VER_UE4_64BIT_EXPORTMAP_SERIALSIZES) + { + writer.Write((int)us.SerialSize); + writer.Write((int)us.SerialOffset); + } + else + { + writer.Write(us.SerialSize); + writer.Write(us.SerialOffset); + } + writer.Write(us.bForcedExport ? 1 : 0); + writer.Write(us.bNotForClient ? 1 : 0); + writer.Write(us.bNotForServer ? 1 : 0); + writer.Write(us.PackageGuid.ToByteArray()); + writer.Write((uint)us.PackageFlags); + if (EngineVersion >= UE4Version.VER_UE4_LOAD_FOR_EDITOR_GAME) + { + writer.Write(us.bNotAlwaysLoadedForEditorGame ? 1 : 0); + } + if (EngineVersion >= UE4Version.VER_UE4_COOKED_ASSETS_IN_EDITOR_SUPPORT) + { + writer.Write(us.bIsAsset ? 1 : 0); + } + if (EngineVersion >= UE4Version.VER_UE4_PRELOAD_DEPENDENCIES_IN_COOKED_EXPORTS) + { + writer.Write(us.FirstExportDependencyOffset); + writer.Write(us.SerializationBeforeSerializationDependenciesSize); + writer.Write(us.CreateBeforeSerializationDependenciesSize); + writer.Write(us.SerializationBeforeCreateDependenciesSize); + writer.Write(us.CreateBeforeCreateDependenciesSize); + } + } + } + else + { + this.ExportOffset = 0; + } + + // DependsMap + if (this.doWeHaveDependsMap) + { + this.DependsOffset = (int)writer.BaseStream.Position; + for (int i = 0; i < this.Exports.Count; i++) + { + if (i >= this.DependsMap.Count) this.DependsMap.Add(new int[0]); + + int[] currentData = this.DependsMap[i]; + writer.Write(currentData.Length); + for (int j = 0; j < currentData.Length; j++) + { + writer.Write(currentData[j]); + } + } + } + else + { + this.DependsOffset = 0; + } + + // SoftPackageReferenceList + if (this.doWeHaveSoftPackageReferences) + { + this.SoftPackageReferencesOffset = (int)writer.BaseStream.Position; + this.SoftPackageReferencesCount = this.SoftPackageReferenceList.Count; + for (int i = 0; i < this.SoftPackageReferenceList.Count; i++) + { + writer.Write(this.SoftPackageReferenceList[i]); + } + } + else + { + this.SoftPackageReferencesOffset = 0; + } + + // AssetRegistryData + if (this.doWeHaveAssetRegistryData) + { + this.AssetRegistryDataOffset = (int)writer.BaseStream.Position; + writer.Write(this.AssetRegistryData.Count); +#pragma warning disable CS0162 // Unreachable code detected + for (int i = 0; i < this.AssetRegistryData.Count; i++) + { + throw new NotImplementedException("Asset registry data is not yet supported. Please let me know if you see this error message"); + } +#pragma warning restore CS0162 // Unreachable code detected + } + else + { + this.AssetRegistryDataOffset = 0; + } + + // WorldTileInfo + if (this.doWeHaveWorldTileInfo) + { + this.WorldTileInfoDataOffset = (int)writer.BaseStream.Position; + WorldTileInfo.Write(writer, this); + } + else + { + this.WorldTileInfoDataOffset = 0; + } + + // PreloadDependencies + this.PreloadDependencyOffset = (int)writer.BaseStream.Position; + if (this.UseSeparateBulkDataFiles) + { + this.PreloadDependencyCount = 0; + for (int i = 0; i < this.Exports.Count; i++) + { + Exports[i].FirstExportDependencyOffset = this.PreloadDependencyCount; + + Exports[i].SerializationBeforeSerializationDependenciesSize = Exports[i].SerializationBeforeSerializationDependencies.Count; + for (int j = 0; j < Exports[i].SerializationBeforeSerializationDependenciesSize; j++) writer.Write(Exports[i].SerializationBeforeSerializationDependencies[j].Index); + + Exports[i].CreateBeforeSerializationDependenciesSize = Exports[i].CreateBeforeSerializationDependencies.Count; + for (int j = 0; j < Exports[i].CreateBeforeSerializationDependenciesSize; j++) writer.Write(Exports[i].CreateBeforeSerializationDependencies[j].Index); + + Exports[i].SerializationBeforeCreateDependenciesSize = Exports[i].SerializationBeforeCreateDependencies.Count; + for (int j = 0; j < Exports[i].SerializationBeforeCreateDependenciesSize; j++) writer.Write(Exports[i].SerializationBeforeCreateDependencies[j].Index); + + Exports[i].CreateBeforeCreateDependenciesSize = Exports[i].CreateBeforeCreateDependencies.Count; + for (int j = 0; j < Exports[i].CreateBeforeCreateDependenciesSize; j++) writer.Write(Exports[i].CreateBeforeCreateDependencies[j].Index); + + this.PreloadDependencyCount += + Exports[i].SerializationBeforeSerializationDependencies.Count + + Exports[i].CreateBeforeSerializationDependencies.Count + + Exports[i].SerializationBeforeCreateDependencies.Count + + Exports[i].CreateBeforeCreateDependencies.Count; + } + } + else + { + this.PreloadDependencyCount = -1; + for (int i = 0; i < this.Exports.Count; i++) Exports[i].FirstExportDependencyOffset = -1; + } + + // Export data + int oldOffset = this.SectionSixOffset; + this.SectionSixOffset = (int)writer.BaseStream.Position; + long[] categoryStarts = new long[this.Exports.Count]; + if (this.Exports.Count > 0) + { + for (int i = 0; i < this.Exports.Count; i++) + { + categoryStarts[i] = writer.BaseStream.Position; + Export us = this.Exports[i]; + us.Write(writer); + writer.Write(us.Extras); + } + } + writer.Write(new byte[] { 0xC1, 0x83, 0x2A, 0x9E }); + + this.BulkDataStartOffset = (int)stre.Length - 4; + + // Rewrite Section 3 + if (this.Exports.Count > 0) + { + writer.Seek(this.ExportOffset, SeekOrigin.Begin); + for (int i = 0; i < this.Exports.Count; i++) + { + Export us = this.Exports[i]; + long nextLoc = this.BulkDataStartOffset; + if ((this.Exports.Count - 1) > i) nextLoc = categoryStarts[i + 1]; + + us.SerialOffset = categoryStarts[i]; + us.SerialSize = nextLoc - categoryStarts[i]; + + writer.Write(us.ClassIndex.Index); + writer.Write(us.SuperIndex.Index); + if (EngineVersion >= UE4Version.VER_UE4_TemplateIndex_IN_COOKED_EXPORTS) + { + writer.Write(us.TemplateIndex.Index); + } + writer.Write(us.OuterIndex.Index); + writer.Write(us.ObjectName); + writer.Write((uint)us.ObjectFlags); + if (EngineVersion < UE4Version.VER_UE4_64BIT_EXPORTMAP_SERIALSIZES) + { + writer.Write((int)us.SerialSize); + writer.Write((int)us.SerialOffset); + } + else + { + writer.Write(us.SerialSize); + writer.Write(us.SerialOffset); + } + writer.Write(us.bForcedExport ? 1 : 0); + writer.Write(us.bNotForClient ? 1 : 0); + writer.Write(us.bNotForServer ? 1 : 0); + writer.Write(us.PackageGuid.ToByteArray()); + writer.Write((uint)us.PackageFlags); + if (EngineVersion >= UE4Version.VER_UE4_LOAD_FOR_EDITOR_GAME) + { + writer.Write(us.bNotAlwaysLoadedForEditorGame ? 1 : 0); + } + if (EngineVersion >= UE4Version.VER_UE4_COOKED_ASSETS_IN_EDITOR_SUPPORT) + { + writer.Write(us.bIsAsset ? 1 : 0); + } + if (EngineVersion >= UE4Version.VER_UE4_PRELOAD_DEPENDENCIES_IN_COOKED_EXPORTS) + { + writer.Write(us.FirstExportDependencyOffset); + writer.Write(us.SerializationBeforeSerializationDependenciesSize); + writer.Write(us.CreateBeforeSerializationDependenciesSize); + writer.Write(us.SerializationBeforeCreateDependenciesSize); + writer.Write(us.CreateBeforeCreateDependenciesSize); + } + } + } + + // Rewrite Header + writer.Seek(0, SeekOrigin.Begin); + writer.Write(MakeHeader()); + + writer.Seek(0, SeekOrigin.Begin); + } + finally + { + isSerializationTime = false; + } + return stre; + } + + /// + /// Creates a MemoryStream from an asset path. + /// + /// The path to the input file. + /// A new MemoryStream that stores the binary data of the input file. + public MemoryStream PathToStream(string p) + { + using (FileStream origStream = File.Open(p, FileMode.Open)) + { + MemoryStream completeStream = new MemoryStream(); + origStream.CopyTo(completeStream); + + UseSeparateBulkDataFiles = false; + try + { + var targetFile = Path.ChangeExtension(p, "uexp"); + if (File.Exists(targetFile)) + { + using (FileStream newStream = File.Open(targetFile, FileMode.Open)) + { + completeStream.Seek(0, SeekOrigin.End); + newStream.CopyTo(completeStream); + UseSeparateBulkDataFiles = true; + } + } + } + catch (FileNotFoundException) { } + + completeStream.Seek(0, SeekOrigin.Begin); + return completeStream; + } + } + + /// + /// Creates a BinaryReader from an asset path. + /// + /// The path to the input file. + /// A new BinaryReader that stores the binary data of the input file. + public AssetBinaryReader PathToReader(string p) + { + return new AssetBinaryReader(PathToStream(p), this); + } + + /// + /// Serializes and writes an asset to disk from memory. + /// + /// The path on disk to write the asset to. + /// Thrown when is unspecified. + public void Write(string outputPath) + { + if (EngineVersion == UE4Version.UNKNOWN) throw new UnknownEngineVersionException("Cannot begin serialization before an engine version is specified"); + + MemoryStream newData = WriteData(); + + if (this.UseSeparateBulkDataFiles && this.Exports.Count > 0) + { + long breakingOffPoint = this.Exports[0].SerialOffset; + using (FileStream f = File.Open(outputPath, FileMode.Create, FileAccess.Write)) + { + CopySplitUp(newData, f, 0, (int)breakingOffPoint); + } + + using (FileStream f = File.Open(Path.ChangeExtension(outputPath, "uexp"), FileMode.Create, FileAccess.Write)) + { + CopySplitUp(newData, f, (int)breakingOffPoint, (int)(newData.Length - breakingOffPoint)); + } + } + else + { + using (FileStream f = File.Open(outputPath, FileMode.Create, FileAccess.Write)) + { + newData.CopyTo(f); + } + } + } + + internal static JsonSerializerSettings jsonSettings = new JsonSerializerSettings + { + TypeNameHandling = TypeNameHandling.Objects, + NullValueHandling = NullValueHandling.Include, + FloatParseHandling = FloatParseHandling.Double, + ReferenceLoopHandling = ReferenceLoopHandling.Ignore, + ContractResolver = new UAssetContractResolver(null), + Converters = new List() + { + new FSignedZeroJsonConverter(), + new FNameJsonConverter(null), + new FStringTableJsonConverter(), + new FStringJsonConverter(), + new FPackageIndexJsonConverter(), + new StringEnumConverter() + } + }; + + /// + /// Serializes this asset as JSON. + /// + /// The formatting to use for the returned JSON string. + /// A serialized JSON string that represents the asset. + public string SerializeJson(Formatting jsonFormatting = Formatting.None) + { + Info = "Serialized with UAssetAPI " + typeof(PropertyData).Assembly.GetName().Version + (string.IsNullOrEmpty(UAPUtils.CurrentCommit) ? "" : (" (" + UAPUtils.CurrentCommit + ")")); + return JsonConvert.SerializeObject(this, jsonFormatting, jsonSettings); + } + + /// + /// Reads an asset from serialized JSON and initializes a new instance of the class to store its data in memory. + /// + /// A serialized JSON string to parse. + public static UAsset DeserializeJson(string json) + { + Dictionary toBeFilled = new Dictionary(); + UAsset res = JsonConvert.DeserializeObject(json, new JsonSerializerSettings + { + TypeNameHandling = TypeNameHandling.Objects, + NullValueHandling = NullValueHandling.Include, + FloatParseHandling = FloatParseHandling.Double, + ReferenceLoopHandling = ReferenceLoopHandling.Ignore, + ContractResolver = new UAssetContractResolver(toBeFilled), + Converters = new List() + { + new FSignedZeroJsonConverter(), + new FNameJsonConverter(null), + new FStringTableJsonConverter(), + new FStringJsonConverter(), + new FPackageIndexJsonConverter(), + new StringEnumConverter() + } + }); + + foreach (KeyValuePair entry in toBeFilled) + { + entry.Key.Asset = res; + if (entry.Value == string.Empty) + { + entry.Key.DummyValue = new FString(entry.Value); + } + else + { + var dummy = FName.FromString(res, entry.Value); + entry.Key.Value = dummy.Value; + entry.Key.Number = dummy.Number; + } + } + toBeFilled.Clear(); + + foreach (Export ex in res.Exports) ex.Asset = res; + return res; + } + + /// + /// Reads an asset from serialized JSON and initializes a new instance of the class to store its data in memory. + /// + /// A stream containing serialized JSON string to parse. + public static UAsset DeserializeJson(Stream stream) + { + Dictionary toBeFilled = new Dictionary(); + var serializer = JsonSerializer.Create(new JsonSerializerSettings + { + TypeNameHandling = TypeNameHandling.Objects, + NullValueHandling = NullValueHandling.Include, + FloatParseHandling = FloatParseHandling.Double, + ReferenceLoopHandling = ReferenceLoopHandling.Ignore, + ContractResolver = new UAssetContractResolver(toBeFilled), + Converters = new List() + { + new FSignedZeroJsonConverter(), + new FNameJsonConverter(null), + new FStringTableJsonConverter(), + new FStringJsonConverter(), + new FPackageIndexJsonConverter(), + new StringEnumConverter() + } + }); + + UAsset res; + + using (var sr = new StreamReader(stream)) + { + using (var jsonTextReader = new JsonTextReader(sr)) + { + res = serializer.Deserialize(jsonTextReader); + } + } + + foreach (KeyValuePair entry in toBeFilled) + { + entry.Key.Asset = res; + if (entry.Value == string.Empty) + { + entry.Key.DummyValue = new FString(entry.Value); + } + else + { + var dummy = FName.FromString(res, entry.Value); + entry.Key.Value = dummy.Value; + entry.Key.Number = dummy.Number; + } + } + toBeFilled.Clear(); + + foreach (Export ex in res.Exports) ex.Asset = res; + return res; + } + + /// + /// Reads an asset from disk and initializes a new instance of the class to store its data in memory. + /// + /// The path of the asset file on disk that this instance will read from. + /// The version of the Unreal Engine that will be used to parse this asset. If the asset is versioned, this can be left unspecified. + /// A list of custom versions to parse this asset with. A list of custom versions will automatically be derived from the engine version while parsing if necessary, but you may manually specify them anyways if you wish. If the asset is versioned, this can be left unspecified. + /// Thrown when this is an unversioned asset and is unspecified. + /// Throw when the asset cannot be parsed correctly. + public UAsset(string path, UE4Version engineVersion = UE4Version.UNKNOWN, List defaultCustomVersionContainer = null) + { + this.FilePath = path; + EngineVersion = engineVersion; + CustomVersionContainer = defaultCustomVersionContainer; + + Read(PathToReader(path)); + } + + /// + /// Reads an asset from a BinaryReader and initializes a new instance of the class to store its data in memory. + /// + /// The asset's BinaryReader that this instance will read from. + /// The version of the Unreal Engine that will be used to parse this asset. If the asset is versioned, this can be left unspecified. + /// A list of custom versions to parse this asset with. A list of custom versions will automatically be derived from the engine version while parsing if necessary, but you may manually specify them anyways if you wish. If the asset is versioned, this can be left unspecified. + /// Thrown when this is an unversioned asset and is unspecified. + /// Throw when the asset cannot be parsed correctly. + public UAsset(AssetBinaryReader reader, UE4Version engineVersion = UE4Version.UNKNOWN, List defaultCustomVersionContainer = null) + { + EngineVersion = engineVersion; + CustomVersionContainer = defaultCustomVersionContainer; + Read(reader); + } + + /// + /// Initializes a new instance of the class. This instance will store no asset data and does not represent any asset in particular until the method is manually called. + /// + /// The version of the Unreal Engine that will be used to parse this asset. If the asset is versioned, this can be left unspecified. + /// A list of custom versions to parse this asset with. A list of custom versions will automatically be derived from the engine version while parsing if necessary, but you may manually specify them anyways if you wish. If the asset is versioned, this can be left unspecified. + public UAsset(UE4Version engineVersion = UE4Version.UNKNOWN, List defaultCustomVersionContainer = null) + { + EngineVersion = engineVersion; + CustomVersionContainer = defaultCustomVersionContainer; + } + + /// + /// Initializes a new instance of the class. This instance will store no asset data and does not represent any asset in particular until the method is manually called. + /// + public UAsset() + { + + } + } +} diff --git a/Translation/UAssetAPI/UAssetAPI.csproj b/Translation/UAssetAPI/UAssetAPI.csproj new file mode 100644 index 0000000..cbaaee3 --- /dev/null +++ b/Translation/UAssetAPI/UAssetAPI.csproj @@ -0,0 +1,38 @@ + + + netstandard2.1 + Library + false + + + bin\Debug\UAssetAPI.xml + 1591 + + + + True + True + Resources.resx + + + + + + 13.0.2-beta2 + + + + all + + + + + ResXFileCodeGenerator + Resources.Designer.cs + + + + + + + \ No newline at end of file diff --git a/Translation/UAssetAPI/UnrealTypes/FFieldPath.cs b/Translation/UAssetAPI/UnrealTypes/FFieldPath.cs new file mode 100644 index 0000000..76a638d --- /dev/null +++ b/Translation/UAssetAPI/UnrealTypes/FFieldPath.cs @@ -0,0 +1,32 @@ +using Newtonsoft.Json; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.UnrealTypes +{ + [JsonObject(MemberSerialization.OptIn)] + public class FFieldPath + { + /// + /// Path to the FField object from the innermost FField to the outermost UObject (UPackage) + /// + [JsonProperty] + public FName[] Path; + + /// + /// The cached owner of this field. + /// + [JsonProperty] + public FPackageIndex ResolvedOwner; + + public FFieldPath(FName[] path, FPackageIndex resolvedOwner) + { + Path = path; + ResolvedOwner = resolvedOwner; + } + + public FFieldPath() + { + + } + } +} diff --git a/Translation/UAssetAPI/UnrealTypes/FName.cs b/Translation/UAssetAPI/UnrealTypes/FName.cs new file mode 100644 index 0000000..ada254d --- /dev/null +++ b/Translation/UAssetAPI/UnrealTypes/FName.cs @@ -0,0 +1,223 @@ +using Newtonsoft.Json; +using System; +using System.Text; +using UAssetAPI.JSON; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.UnrealTypes +{ + /// + /// Unreal name - consists of an FString (which is serialized as an index in the name map) and an instance number + /// + [JsonConverter(typeof(FNameJsonConverter))] + public class FName : ICloneable + { + public FString Value + { + get + { + if (DummyValue != null) return DummyValue; + if (Asset == null) throw new InvalidOperationException("Attempt to get Value with no Asset defined"); + if (Index < 0) return null; + return Asset.GetNameReference(Index); + } + set + { + DummyValue = null; + if (Asset == null) throw new InvalidOperationException("Attempt to set Value with no Asset defined"); + Index = value?.Value == null ? -1 : Asset.AddNameReference(value); + } + } + + public bool IsDummy + { + get + { + return DummyValue != null; + } + } + + /// Instance number. + public int Number; + + /// + /// The asset that this FName is bound to. + /// + public UAsset Asset; + + /// + /// Index into the name map of that this FName points to. + /// + internal int Index; + + /// + /// Dummy value. If defined, this FName does not actually point to a value in the name map, but will still act as if it does. Used for debugging and display only. + /// + internal FString DummyValue = null; + + /// + /// Converts this FName instance into a human-readable string. This is the inverse of . + /// + /// The human-readable string that represents this FName. + public override string ToString() + { + if (Number > 0) return Value.ToString() + "_" + (Number - 1); + return Value.ToString(); + } + + /// + /// Converts a human-readable string into an FName instance. This is the inverse of . + /// + /// The asset that the new FName will be bound to. + /// The human-readable string to convert into an FName instance. + /// An FName instance that this string represents. + public static FName FromString(UAsset asset, string val) + { + if (val == null || val == FString.NullCase) return null; + if (val.Length == 0) return new FName(asset, val, 0); + + if (val[val.Length - 1] >= '0' && val[val.Length - 1] <= '9') + { + int i = val.Length - 1; + while (i > 1 && (val[i] >= '0' && val[i] <= '9')) + { + i--; + } + + if (val[i] == '_') + { + string startSegment = val.Substring(0, i); + string endSegment = val.Substring(i + 1, val.Length - i - 1); + if (endSegment.Length == 1 || endSegment[0] != '0') + { + if (int.TryParse(endSegment, out int endSegmentVal)) return new FName(asset, startSegment, endSegmentVal + 1); + } + } + } + + return new FName(asset, val, 0); + } + + /// + /// Creates a new FName with the same string value and number as the current instance but is bound to a different asset. + /// + /// The asset to bound the new FName to. + /// An equivalent FName bound to a different asset. + public FName Transfer(UAsset newAsset) + { + return new FName(newAsset, Value, Number); + } + + public static FName DefineDummy(UAsset asset, FString val, int number = 0) + { + var res = new FName(); + res.Asset = asset; + res.DummyValue = val; + res.Number = number; + return res; + } + + public static FName DefineDummy(UAsset asset, string val, int number = 0) + { + var res = new FName(); + res.Asset = asset; + res.DummyValue = FString.FromString(val); + res.Number = number; + return res; + } + + public override bool Equals(object obj) + { + if (!(obj is FName name)) return false; + if (this is null || obj is null) return this is null && obj is null; + return (this.Value == name.Value || this.Value.Value == name.Value.Value) && this.Number == name.Number; + } + + public static bool operator ==(FName one, FName two) + { + if (one is null || two is null) return one is null && two is null; + return one.Equals(two); + } + + public static bool operator !=(FName one, FName two) + { + if (one is null || two is null) return !(one is null && two is null); + return !one.Equals(two); + } + + public override int GetHashCode() + { + return Value == null ? 0 : (Value.GetHashCode() ^ Number.GetHashCode()); + } + + public object Clone() + { + return new FName(Asset, (FString)Value.Clone(), Number); + } + + /// + /// Creates a new FName instance. + /// + /// The asset that this FName is bound to. + /// The string literal that the new FName's value will be, verbatim. + /// The instance number of the new FName. + public FName(UAsset asset, string value, int number = 0) + { + Asset = asset; + if (value == null) + { + Value = new FString(null); + } + else + { + Value = new FString(value); + } + Number = number; + } + + /// + /// Creates a new FName instance. + /// + /// The asset that this FName is bound to. + /// The FString that the FName's value will be, verbatim. + /// The instance number of the new FName. + public FName(UAsset asset, FString value, int number = 0) + { + Asset = asset; + Value = value; + Number = number; + } + + /// + /// Creates a new FName instance. + /// + /// The asset that this FName is bound to. + /// The index that this FName's value will be. + /// The instance number of the new FName. + public FName(UAsset asset, int index, int number = 0) + { + Asset = asset; + Index = index; + Number = number; + } + + /// + /// Creates a new blank FName instance. + /// + /// The asset that this FName is bound to. + public FName(UAsset asset) + { + Asset = asset; + Value = new FString(string.Empty); + Number = 0; + } + + /// + /// Creates a new blank FName instance, with no asset bound to it. An asset must be bound to this FName before setting its value. + /// + public FName() + { + Number = 0; + } + } +} diff --git a/Translation/UAssetAPI/UnrealTypes/FObjectResource.cs b/Translation/UAssetAPI/UnrealTypes/FObjectResource.cs new file mode 100644 index 0000000..52f16fd --- /dev/null +++ b/Translation/UAssetAPI/UnrealTypes/FObjectResource.cs @@ -0,0 +1,29 @@ +namespace UAssetAPI.UnrealTypes +{ + /// + /// Base class for UObject resource types. FObjectResources are used to store UObjects on disk + /// via the import map (for resources contained in other packages) and export map (for resources + /// contained within the same package). + /// + public class FObjectResource + { + ///The name of the UObject represented by this resource. + [DisplayIndexOrder(0)] + public FName ObjectName; + + ///Location of the resource for this resource's Outer (import/other export). 0 = this resource is a top-level UPackage + [DisplayIndexOrder(1)] + public FPackageIndex OuterIndex; + + public FObjectResource(FName objectName, FPackageIndex outerIndex) + { + ObjectName = objectName; + OuterIndex = outerIndex; + } + + public FObjectResource() + { + + } + } +} diff --git a/Translation/UAssetAPI/UnrealTypes/FPackageIndex.cs b/Translation/UAssetAPI/UnrealTypes/FPackageIndex.cs new file mode 100644 index 0000000..11348a6 --- /dev/null +++ b/Translation/UAssetAPI/UnrealTypes/FPackageIndex.cs @@ -0,0 +1,159 @@ +using Newtonsoft.Json; +using System; +using UAssetAPI.JSON; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.UnrealTypes +{ + /// + /// Wrapper for index into an ImportMap or ExportMap. + /// + /// Values greater than zero indicate that this is an index into the ExportMap. + /// The actual array index will be (FPackageIndex - 1). + /// + /// Values less than zero indicate that this is an index into the ImportMap. + /// The actual array index will be (-FPackageIndex - 1) + /// + [JsonConverter(typeof(FPackageIndexJsonConverter))] + public class FPackageIndex + { + /// + /// Values greater than zero indicate that this is an index into the ExportMap. + /// The actual array index will be (FPackageIndex - 1). + /// + /// Values less than zero indicate that this is an index into the ImportMap. + /// The actual array index will be (-FPackageIndex - 1) + /// + public int Index; + + /// + /// Returns an FPackageIndex based off of the index provided. Equivalent to . + /// + /// The index to create a new FPackageIndex with. + /// A new FPackageIndex with the index provided. + public static FPackageIndex FromRawIndex(int index) + { + return new FPackageIndex(index); + } + + /// + /// Returns true if this is an index into the import map. + /// + /// true if this is an index into the import map, false otherwise + public bool IsImport() + { + return Index < 0; + } + + /// + /// Returns true if this is an index into the export map. + /// + /// true if this is an index into the export map, false otherwise + public bool IsExport() + { + return Index > 0; + } + + /// + /// Return true if this represents null (i.e. neither an import nor an export) + /// + /// true if this index represents null, false otherwise + public bool IsNull() + { + return this == null || Index == 0; + } + + /// + /// Creates a FPackageIndex from an index in the import map. + /// + /// An import index to create an FPackageIndex from. + /// An FPackageIndex created from the import index. + /// Thrown when the provided import index is less than zero. + public static FPackageIndex FromImport(int importIndex) + { + if (importIndex < 0) throw new InvalidOperationException("importIndex must be greater than or equal to zero"); + return new FPackageIndex(-importIndex - 1); + } + + /// + /// Creates a FPackageIndex from an index in the export map. + /// + /// An export index to create an FPackageIndex from. + /// An FPackageIndex created from the export index. + /// Thrown when the provided export index is less than zero. + public static FPackageIndex FromExport(int exportIndex) + { + if (exportIndex < 0) throw new InvalidOperationException("exportIndex must be greater than or equal to zero"); + return new FPackageIndex(exportIndex + 1); + } + + /// + /// Check that this is an import index and return the corresponding import. + /// + /// The asset that this index is used in. + /// The import that this index represents in the import map. + /// Thrown when this is not an index into the import map. + public Import ToImport(UAsset asset) + { + if (!IsImport()) throw new InvalidOperationException("Index = " + Index + "; cannot call ToImport()"); + int newIndex = -Index - 1; + if (newIndex < 0 || newIndex >= asset.Imports.Count) return null; + return asset.Imports[newIndex]; + } + + /// + /// Check that this is an export index and return the corresponding export. + /// + /// The asset that this index is used in. + /// The export that this index represents in the the export map. + /// Thrown when this is not an index into the export map. + public Export ToExport(UAsset asset) + { + if (!IsExport()) throw new InvalidOperationException("Index = " + Index + "; cannot call ToExport()"); + int newIndex = Index - 1; + if (newIndex < 0 || newIndex >= asset.Exports.Count) return null; + return asset.Exports[newIndex]; + } + + public override bool Equals(object obj) + { + if (!(obj is FPackageIndex comparingPackageIndex)) return false; + return comparingPackageIndex.Index == this.Index; + } + + public static bool operator <(FPackageIndex first, FPackageIndex second) + { + return first.Index < second.Index; + } + + public static bool operator >(FPackageIndex first, FPackageIndex second) + { + return first.Index > second.Index; + } + + public static bool operator <=(FPackageIndex first, FPackageIndex second) + { + return first.Index <= second.Index; + } + + public static bool operator >=(FPackageIndex first, FPackageIndex second) + { + return first.Index >= second.Index; + } + + public override int GetHashCode() + { + return Index.GetHashCode(); + } + + public override string ToString() + { + return Index.ToString(); + } + + public FPackageIndex(int index = 0) + { + Index = index; + } + } +} diff --git a/Translation/UAssetAPI/UnrealTypes/FQuat.cs b/Translation/UAssetAPI/UnrealTypes/FQuat.cs new file mode 100644 index 0000000..c720f97 --- /dev/null +++ b/Translation/UAssetAPI/UnrealTypes/FQuat.cs @@ -0,0 +1,47 @@ +using Newtonsoft.Json; +using UAssetAPI.JSON; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.UnrealTypes +{ + /// + /// Floating point quaternion that can represent a rotation about an axis in 3-D space. + /// The X, Y, Z, W components also double as the Axis/Angle format. + /// + [JsonObject(MemberSerialization.OptIn)] + public class FQuat + { + /// The quaternion's X-component. + [JsonProperty] + [JsonConverter(typeof(FSignedZeroJsonConverter))] + public float X; + + /// The quaternion's Y-component. + [JsonProperty] + [JsonConverter(typeof(FSignedZeroJsonConverter))] + public float Y; + + /// The quaternion's Z-component. + [JsonProperty] + [JsonConverter(typeof(FSignedZeroJsonConverter))] + public float Z; + + /// The quaternion's W-component. + [JsonProperty] + [JsonConverter(typeof(FSignedZeroJsonConverter))] + public float W; + + public FQuat(float x, float y, float z, float w) + { + X = x; + Y = y; + Z = z; + W = w; + } + + public FQuat() + { + + } + } +} diff --git a/Translation/UAssetAPI/UnrealTypes/FRotator.cs b/Translation/UAssetAPI/UnrealTypes/FRotator.cs new file mode 100644 index 0000000..8beef14 --- /dev/null +++ b/Translation/UAssetAPI/UnrealTypes/FRotator.cs @@ -0,0 +1,41 @@ +using Newtonsoft.Json; +using UAssetAPI.JSON; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.UnrealTypes +{ + /// + /// Implements a container for rotation information. + /// All rotation values are stored in degrees. + /// + [JsonObject(MemberSerialization.OptIn)] + public class FRotator + { + /// Rotation around the right axis (around Y axis), Looking up and down (0=Straight Ahead, +Up, -Down) + [JsonProperty] + [JsonConverter(typeof(FSignedZeroJsonConverter))] + public float Pitch; + + /// Rotation around the up axis (around Z axis), Running in circles 0=East, +North, -South. + [JsonProperty] + [JsonConverter(typeof(FSignedZeroJsonConverter))] + public float Yaw; + + /// Rotation around the forward axis (around X axis), Tilting your head, 0=Straight, +Clockwise, -CCW. + [JsonProperty] + [JsonConverter(typeof(FSignedZeroJsonConverter))] + public float Roll; + + public FRotator(float pitch, float yaw, float roll) + { + Pitch = pitch; + Yaw = yaw; + Roll = roll; + } + + public FRotator() + { + + } + } +} diff --git a/Translation/UAssetAPI/UnrealTypes/FString.cs b/Translation/UAssetAPI/UnrealTypes/FString.cs new file mode 100644 index 0000000..3034317 --- /dev/null +++ b/Translation/UAssetAPI/UnrealTypes/FString.cs @@ -0,0 +1,84 @@ +using Newtonsoft.Json; +using System; +using System.Text; +using UAssetAPI.JSON; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.UnrealTypes +{ + /// + /// Unreal string - consists of a string and an encoding + /// + [JsonConverter(typeof(FStringJsonConverter))] + public class FString : ICloneable + { + public string Value; + public Encoding Encoding; + public static readonly string NullCase = "null"; + + public override string ToString() + { + if (this == null || Value == null) return NullCase; + return Value; + } + + public override bool Equals(object obj) + { + if (obj is FString fStr) + { + if (fStr == null) return false; + return this.Value == fStr.Value && this.Encoding == fStr.Encoding; + } + else if (obj is string str) + { + return this.Value == str; + } + + return false; + } + + public static explicit operator FString(string b) => new FString(b, null); + + public static bool operator ==(FString one, FString two) + { + if (one is null || two is null) return one is null && two is null; + return one.Equals(two); + } + + public static bool operator !=(FString one, FString two) + { + if (one is null || two is null) return !(one is null && two is null); + return !one.Equals(two); + } + + public override int GetHashCode() + { + return Value.GetHashCode(); + } + + public object Clone() + { + return new FString(Value, Encoding); + } + + public static FString FromString(string value, Encoding encoding = null) + { + if (value == NullCase || value == null) return null; + return new FString(value, encoding); + } + + public FString(string value, Encoding encoding = null) + { + if (encoding == null) encoding = Encoding.UTF8.GetByteCount(value) == value.Length ? Encoding.ASCII : Encoding.Unicode; + + Value = value; + Encoding = encoding; + } + + public FString() + { + + } + } + +} diff --git a/Translation/UAssetAPI/UnrealTypes/FTransform.cs b/Translation/UAssetAPI/UnrealTypes/FTransform.cs new file mode 100644 index 0000000..7d9b8e7 --- /dev/null +++ b/Translation/UAssetAPI/UnrealTypes/FTransform.cs @@ -0,0 +1,53 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.UnrealTypes +{ + /// + /// Transform composed of Scale, Rotation (as a quaternion), and Translation. + /// Transforms can be used to convert from one space to another, for example by transforming + /// positions and directions from local space to world space. + /// + /// Transformation of position vectors is applied in the order: Scale -> Rotate -> Translate. + /// Transformation of direction vectors is applied in the order: Scale -> Rotate. + /// + /// Order matters when composing transforms: C = A * B will yield a transform C that logically + /// first applies A then B to any subsequent transformation. Note that this is the opposite order of quaternion (FQuat) multiplication. + /// + /// Example: LocalToWorld = (DeltaRotation * LocalToWorld) will change rotation in local space by DeltaRotation. + /// Example: LocalToWorld = (LocalToWorld * DeltaRotation) will change rotation in world space by DeltaRotation. + /// + [JsonObject(MemberSerialization.OptIn)] + public struct FTransform + { + /// + /// Rotation of this transformation, as a quaternion + /// + [JsonProperty] + public FQuat Rotation; + + /// + /// Translation of this transformation, as a vector. + /// + [JsonProperty] + public FVector Translation; + + /// + /// 3D scale (always applied in local space) as a vector. + /// + [JsonProperty] + public FVector Scale3D; + + public FTransform(FQuat rotation, FVector translation, FVector scale3D) + { + Rotation = rotation; + Translation = translation; + Scale3D = scale3D; + } + } +} diff --git a/Translation/UAssetAPI/UnrealTypes/FVector.cs b/Translation/UAssetAPI/UnrealTypes/FVector.cs new file mode 100644 index 0000000..cb11658 --- /dev/null +++ b/Translation/UAssetAPI/UnrealTypes/FVector.cs @@ -0,0 +1,39 @@ +using Newtonsoft.Json; +using UAssetAPI.JSON; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.UnrealTypes +{ + /// + /// A vector in 3-D space composed of components (X, Y, Z) with floating point precision. + /// + public class FVector + { + /// Vector's X-component. + [JsonProperty] + [JsonConverter(typeof(FSignedZeroJsonConverter))] + public float X; + + /// Vector's Y-component. + [JsonProperty] + [JsonConverter(typeof(FSignedZeroJsonConverter))] + public float Y; + + /// Vector's Z-component. + [JsonProperty] + [JsonConverter(typeof(FSignedZeroJsonConverter))] + public float Z; + + public FVector(float x, float y, float z) + { + X = x; + Y = y; + Z = z; + } + + public FVector() + { + + } + } +} diff --git a/Translation/UAssetAPI/UnrealTypes/FWorldTileInfo.cs b/Translation/UAssetAPI/UnrealTypes/FWorldTileInfo.cs new file mode 100644 index 0000000..9fe95cc --- /dev/null +++ b/Translation/UAssetAPI/UnrealTypes/FWorldTileInfo.cs @@ -0,0 +1,264 @@ +using System.IO; +using UAssetAPI.PropertyTypes.Structs; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.UnrealTypes +{ + /// + /// World layer information for tile tagging + /// + public class FWorldTileLayer + { + /// Human readable name for this layer + public FString Name; + + /// Reserved for additional options + public int Reserved0; + /// Reserved for additional options + public IntPointPropertyData Reserved1; + + /// Distance starting from where tiles belonging to this layer will be streamed in + public int StreamingDistance; + public bool DistanceStreamingEnabled; + + public void Read(AssetBinaryReader reader, UAsset asset) + { + Name = reader.ReadFString(); + Reserved0 = reader.ReadInt32(); + Reserved1 = new IntPointPropertyData(FName.DefineDummy(asset, "Reserved1")); + Reserved1.Read(reader, false, 0, 0); + + if (asset.EngineVersion >= UE4Version.VER_UE4_WORLD_LEVEL_INFO_UPDATED) + { + StreamingDistance = reader.ReadInt32(); + } + + if (asset.EngineVersion >= UE4Version.VER_UE4_WORLD_LAYER_ENABLE_DISTANCE_STREAMING) + { + DistanceStreamingEnabled = reader.ReadInt32() == 1; + } + } + + public void Write(AssetBinaryWriter writer, UAsset asset) + { + writer.Write(this.Name); + writer.Write(Reserved0); + Reserved1.Write(writer, false); + + if (asset.EngineVersion >= UE4Version.VER_UE4_WORLD_LEVEL_INFO_UPDATED) + { + writer.Write(StreamingDistance); + } + + if (asset.EngineVersion >= UE4Version.VER_UE4_WORLD_LAYER_ENABLE_DISTANCE_STREAMING) + { + writer.Write(DistanceStreamingEnabled ? 1 : 0); + } + } + + public FWorldTileLayer(FString name, int reserved0, IntPointPropertyData reserved1, int streamingDistance, bool distanceStreamingEnabled) + { + Name = name; + Reserved0 = reserved0; + Reserved1 = reserved1; + StreamingDistance = streamingDistance; + DistanceStreamingEnabled = distanceStreamingEnabled; + } + + public FWorldTileLayer() + { + + } + } + + /// + /// Describes LOD entry in a world tile + /// + public class FWorldTileLODInfo + { + /// Relative to LOD0 streaming distance, absolute distance = LOD0 + StreamingDistanceDelta + public int RelativeStreamingDistance; + + /// Reserved for additional options + public float Reserved0; + /// Reserved for additional options + public float Reserved1; + /// Reserved for additional options + public int Reserved2; + /// Reserved for additional options + public int Reserved3; + + public FWorldTileLODInfo(int relativeStreamingDistance, float reserved0, float reserved1, int reserved2, int reserved3) + { + RelativeStreamingDistance = relativeStreamingDistance; + Reserved0 = reserved0; + Reserved1 = reserved1; + Reserved2 = reserved2; + Reserved3 = reserved3; + } + + public void Read(AssetBinaryReader reader, UAsset asset) + { + RelativeStreamingDistance = reader.ReadInt32(); + Reserved0 = reader.ReadSingle(); + Reserved1 = reader.ReadSingle(); + Reserved2 = reader.ReadInt32(); + Reserved3 = reader.ReadInt32(); + } + + public void Write(AssetBinaryWriter writer, UAsset asset) + { + writer.Write(RelativeStreamingDistance); + writer.Write(Reserved0); + writer.Write(Reserved1); + writer.Write(Reserved2); + writer.Write(Reserved3); + } + + public FWorldTileLODInfo() + { + + } + } + + /// + /// Tile information used by WorldComposition. + /// Defines properties necessary for tile positioning in the world. Stored with package summary + /// + public class FWorldTileInfo + { + /// Tile position in the world relative to parent + public int[] Position; // FIntVector + /// Absolute tile position in the world. Calculated in runtime + public int[] AbsolutePosition; // FIntVector + /// Tile bounding box + public BoxPropertyData Bounds; + /// Tile assigned layer + public FWorldTileLayer Layer; + /// Whether to hide sub-level tile in tile view + public bool bHideInTileView; + /// Parent tile package name + public FString ParentTilePackageName; + /// LOD information + public FWorldTileLODInfo[] LODList; + /// Sorting order + public int ZOrder; + + public void Read(AssetBinaryReader reader, UAsset asset) + { + Position = new int[3]; + AbsolutePosition = new int[3]; + + if (asset.GetCustomVersion() < FFortniteMainBranchObjectVersion.WorldCompositionTile3DOffset) + { + Position[0] = reader.ReadInt32(); + Position[1] = reader.ReadInt32(); + Position[2] = 0; + } + else + { + Position[0] = reader.ReadInt32(); + Position[1] = reader.ReadInt32(); + Position[2] = reader.ReadInt32(); + } + Bounds = new BoxPropertyData(FName.DefineDummy(asset, "Bounds")); + Bounds.Read(reader, false, 0, 0); + Layer = new FWorldTileLayer(); + Layer.Read(reader, asset); + + if (asset.EngineVersion >= UE4Version.VER_UE4_WORLD_LEVEL_INFO_UPDATED) + { + bHideInTileView = reader.ReadInt32() == 1; + ParentTilePackageName = reader.ReadFString(); + } + + if (asset.EngineVersion >= UE4Version.VER_UE4_WORLD_LEVEL_INFO_LOD_LIST) + { + int numEntries = reader.ReadInt32(); + LODList = new FWorldTileLODInfo[numEntries]; + for (int i = 0; i < numEntries; i++) + { + LODList[i] = new FWorldTileLODInfo(); + LODList[i].Read(reader, asset); + } + } + + if (asset.EngineVersion >= UE4Version.VER_UE4_WORLD_LEVEL_INFO_ZORDER) + { + ZOrder = reader.ReadInt32(); + } + +#pragma warning disable CS0162 // Unreachable code detected + if (false) // Ar.GetPortFlags() & PPF_DuplicateForPIE + { + AbsolutePosition[0] = reader.ReadInt32(); + AbsolutePosition[1] = reader.ReadInt32(); + AbsolutePosition[2] = reader.ReadInt32(); + } +#pragma warning restore CS0162 // Unreachable code detected + } + + public void Write(AssetBinaryWriter writer, UAsset asset) + { + if (asset.GetCustomVersion() < FFortniteMainBranchObjectVersion.WorldCompositionTile3DOffset) + { + writer.Write(Position[0]); + writer.Write(Position[1]); + } + else + { + writer.Write(Position[0]); + writer.Write(Position[1]); + writer.Write(Position[2]); + } + Bounds.Write(writer, false); + Layer.Write(writer, asset); + + if (asset.EngineVersion >= UE4Version.VER_UE4_WORLD_LEVEL_INFO_UPDATED) + { + writer.Write(bHideInTileView ? 1 : 0); + writer.Write(ParentTilePackageName); + } + + if (asset.EngineVersion >= UE4Version.VER_UE4_WORLD_LEVEL_INFO_LOD_LIST) + { + writer.Write(LODList.Length); + for (int i = 0; i < LODList.Length; i++) + { + LODList[i].Write(writer, asset); + } + } + + if (asset.EngineVersion >= UE4Version.VER_UE4_WORLD_LEVEL_INFO_ZORDER) + { + writer.Write(ZOrder); + } + +#pragma warning disable CS0162 // Unreachable code detected + if (false) // Ar.GetPortFlags() & PPF_DuplicateForPIE + { + writer.Write(AbsolutePosition[0]); + writer.Write(AbsolutePosition[1]); + writer.Write(AbsolutePosition[2]); + } +#pragma warning restore CS0162 // Unreachable code detected + } + + public FWorldTileInfo(int[] position, int[] absolutePosition, BoxPropertyData bounds, FWorldTileLayer layer, bool bHideInTileView, FString parentTilePackageName, FWorldTileLODInfo[] lODList, int zOrder) + { + Position = position; + AbsolutePosition = absolutePosition; + Bounds = bounds; + Layer = layer; + this.bHideInTileView = bHideInTileView; + ParentTilePackageName = parentTilePackageName; + LODList = lODList; + ZOrder = zOrder; + } + + public FWorldTileInfo() + { + + } + } +} diff --git a/Translation/UAssetAPI/UnrealTypes/Flags.cs b/Translation/UAssetAPI/UnrealTypes/Flags.cs new file mode 100644 index 0000000..0afede5 --- /dev/null +++ b/Translation/UAssetAPI/UnrealTypes/Flags.cs @@ -0,0 +1,317 @@ +using System; + +namespace UAssetAPI.UnrealTypes +{ + /// + /// Flags describing an object instance + /// + [Flags] + public enum EObjectFlags + { + RF_NoFlags = 0x00000000, + RF_Public = 0x00000001, + RF_Standalone = 0x00000002, + RF_MarkAsNative = 0x00000004, + RF_Transactional = 0x00000008, + RF_ClassDefaultObject = 0x00000010, + RF_ArchetypeObject = 0x00000020, + RF_Transient = 0x00000040, + RF_MarkAsRootSet = 0x00000080, + RF_TagGarbageTemp = 0x00000100, + RF_NeedInitialization = 0x00000200, + RF_NeedLoad = 0x00000400, + RF_KeepForCooker = 0x00000800, + RF_NeedPostLoad = 0x00001000, + RF_NeedPostLoadSubobjects = 0x00002000, + RF_NewerVersionExists = 0x00004000, + RF_BeginDestroyed = 0x00008000, + RF_FinishDestroyed = 0x00010000, + RF_BeingRegenerated = 0x00020000, + RF_DefaultSubObject = 0x00040000, + RF_WasLoaded = 0x00080000, + RF_TextExportTransient = 0x00100000, + RF_LoadCompleted = 0x00200000, + RF_InheritableComponentTemplate = 0x00400000, + RF_DuplicateTransient = 0x00800000, + RF_StrongRefOnFrame = 0x01000000, + RF_NonPIEDuplicateTransient = 0x02000000, + RF_Dynamic = 0x04000000, + RF_WillBeLoaded = 0x08000000, + RF_HasExternalPackage = 0x10000000 + } + + /// + /// Package flags, passed into UPackage::SetPackageFlags and related functions in the Unreal Engine + /// + [Flags] + public enum EPackageFlags : uint + { + ///No flags + PKG_None = 0x00000000, + ///Newly created package, not saved yet. In editor only. + PKG_NewlyCreated = 0x00000001, + ///Purely optional for clients. + PKG_ClientOptional = 0x00000002, + ///Only needed on the server side. + PKG_ServerSideOnly = 0x00000004, + ///This package is from "compiled in" classes. + PKG_CompiledIn = 0x00000010, + ///This package was loaded just for the purposes of diffing + PKG_ForDiffing = 0x00000020, + ///This is editor-only package (for example: editor module script package) + PKG_EditorOnly = 0x00000040, + ///Developer module + PKG_Developer = 0x00000080, + ///Loaded only in uncooked builds (i.e. runtime in editor) + PKG_UncookedOnly = 0x00000100, + ///Package is cooked + PKG_Cooked = 0x00000200, + ///Package doesn't contain any asset object (although asset tags can be present) + PKG_ContainsNoAsset = 0x00000400, + ///Uses unversioned property serialization instead of versioned tagged property serialization + PKG_UnversionedProperties = 0x00002000, + ///Contains map data (UObjects only referenced by a single ULevel) but is stored in a different package + PKG_ContainsMapData = 0x00004000, + ///package is currently being compiled + PKG_Compiling = 0x00010000, + ///Set if the package contains a ULevel/ UWorld object + PKG_ContainsMap = 0x00020000, + ///??? + PKG_RequiresLocalizationGather = 0x00040000, + ///Set if the package was created for the purpose of PIE + PKG_PlayInEditor = 0x00100000, + ///Package is allowed to contain UClass objects + PKG_ContainsScript = 0x00200000, + ///Editor should not export asset in this package + PKG_DisallowExport = 0x00400000, + ///This package should resolve dynamic imports from its export at runtime. + PKG_DynamicImports = 0x10000000, + ///This package contains elements that are runtime generated, and may not follow standard loading order rules + PKG_RuntimeGenerated = 0x20000000, + ///This package is reloading in the cooker, try to avoid getting data we will never need. We won't save this package. + PKG_ReloadingForCooker = 0x40000000, + ///Package has editor-only data filtered out + PKG_FilterEditorOnly = 0x80000000, + } + + /// + /// Flags associated with each property in a class, overriding the property's default behavior. + /// + [Flags] + public enum EPropertyFlags : ulong + { + CPF_None = 0, + + ///Property is user-settable in the editor. + CPF_Edit = 0x0000000000000001, + ///This is a constant function parameter + CPF_ConstParm = 0x0000000000000002, + ///This property can be read by blueprint code + CPF_BlueprintVisible = 0x0000000000000004, + ///Object can be exported with actor. + CPF_ExportObject = 0x0000000000000008, + ///This property cannot be modified by blueprint code + CPF_BlueprintReadOnly = 0x0000000000000010, + ///Property is relevant to network replication. + CPF_Net = 0x0000000000000020, + ///Indicates that elements of an array can be modified, but its size cannot be changed. + CPF_EditFixedSize = 0x0000000000000040, + ///Function/When call parameter. + CPF_Parm = 0x0000000000000080, + ///Value is copied out after function call. + CPF_OutParm = 0x0000000000000100, + ///memset is fine for construction + CPF_ZeroConstructor = 0x0000000000000200, + ///Return value. + CPF_ReturnParm = 0x0000000000000400, + ///Disable editing of this property on an archetype/sub-blueprint + CPF_DisableEditOnTemplate = 0x0000000000000800, + ///Property is transient: shouldn't be saved or loaded, except for Blueprint CDOs. + CPF_Transient = 0x0000000000002000, + ///Property should be loaded/saved as permanent profile. + CPF_Config = 0x0000000000004000, + ///Disable editing on an instance of this class + CPF_DisableEditOnInstance = 0x0000000000010000, + ///Property is uneditable in the editor. + CPF_EditConst = 0x0000000000020000, + ///Load config from base class, not subclass. + CPF_GlobalConfig = 0x0000000000040000, + ///Property is a component references. + CPF_InstancedReference = 0x0000000000080000, + ///Property should always be reset to the default value during any type of duplication (copy/paste, binary duplication, etc.) + CPF_DuplicateTransient = 0x0000000000200000, + ///Property should be serialized for save games, this is only checked for game-specific archives with ArIsSaveGame + CPF_SaveGame = 0x0000000001000000, + ///Hide clear (and browse) button. + CPF_NoClear = 0x0000000002000000, + ///Value is passed by reference; CPF_OutParam and CPF_Param should also be set. + CPF_ReferenceParm = 0x0000000008000000, + ///MC Delegates only. Property should be exposed for assigning in blueprint code + CPF_BlueprintAssignable = 0x0000000010000000, + ///Property is deprecated. Read it from an archive, but don't save it. + CPF_Deprecated = 0x0000000020000000, + ///If this is set, then the property can be memcopied instead of CopyCompleteValue / CopySingleValue + CPF_IsPlainOldData = 0x0000000040000000, + ///Not replicated. For non replicated properties in replicated structs + CPF_RepSkip = 0x0000000080000000, + ///Notify actors when a property is replicated + CPF_RepNotify = 0x0000000100000000, + ///interpolatable property for use with matinee + CPF_Interp = 0x0000000200000000, + ///Property isn't transacted + CPF_NonTransactional = 0x0000000400000000, + ///Property should only be loaded in the editor + CPF_EditorOnly = 0x0000000800000000, + ///No destructor + CPF_NoDestructor = 0x0000001000000000, + ///Only used for weak pointers, means the export type is autoweak + CPF_AutoWeak = 0x0000004000000000, + ///Property contains component references. + CPF_ContainsInstancedReference = 0x0000008000000000, + ///asset instances will add properties with this flag to the asset registry automatically + CPF_AssetRegistrySearchable = 0x0000010000000000, + ///The property is visible by default in the editor details view + CPF_SimpleDisplay = 0x0000020000000000, + ///The property is advanced and not visible by default in the editor details view + CPF_AdvancedDisplay = 0x0000040000000000, + ///property is protected from the perspective of script + CPF_Protected = 0x0000080000000000, + ///MC Delegates only. Property should be exposed for calling in blueprint code + CPF_BlueprintCallable = 0x0000100000000000, + ///MC Delegates only. This delegate accepts (only in blueprint) only events with BlueprintAuthorityOnly. + CPF_BlueprintAuthorityOnly = 0x0000200000000000, + ///Property shouldn't be exported to text format (e.g. copy/paste) + CPF_TextExportTransient = 0x0000400000000000, + ///Property should only be copied in PIE + CPF_NonPIEDuplicateTransient = 0x0000800000000000, + ///Property is exposed on spawn + CPF_ExposeOnSpawn = 0x0001000000000000, + ///A object referenced by the property is duplicated like a component. (Each actor should have an own instance.) + CPF_PersistentInstance = 0x0002000000000000, + ///Property was parsed as a wrapper class like TSubclassOf T, FScriptInterface etc., rather than a USomething* + CPF_UObjectWrapper = 0x0004000000000000, + ///This property can generate a meaningful hash value. + CPF_HasGetValueTypeHash = 0x0008000000000000, + ///Public native access specifier + CPF_NativeAccessSpecifierPublic = 0x0010000000000000, + ///Protected native access specifier + CPF_NativeAccessSpecifierProtected = 0x0020000000000000, + ///Private native access specifier + CPF_NativeAccessSpecifierPrivate = 0x0040000000000000, + ///Property shouldn't be serialized, can still be exported to text + CPF_SkipSerialization = 0x0080000000000000, + } + + /// + /// Flags describing a class. + /// + [Flags] + public enum EClassFlags : uint + { + /// No Flags + CLASS_None = 0x00000000, + /// Class is abstract and can't be instantiated directly. + CLASS_Abstract = 0x00000001, + /// Save object configuration only to Default INIs, never to local INIs. Must be combined with CLASS_Config + CLASS_DefaultConfig = 0x00000002, + /// Load object configuration at construction time. + CLASS_Config = 0x00000004, + /// This object type can't be saved; null it out at save time. + CLASS_Transient = 0x00000008, + /// Successfully parsed. + CLASS_Parsed = 0x00000010, + /// ??? + CLASS_MatchedSerializers = 0x00000020, + /// Indicates that the config settings for this class will be saved to Project/User*.ini (similar to CLASS_GlobalUserConfig) + CLASS_ProjectUserConfig = 0x00000040, + /// Class is a native class - native interfaces will have CLASS_Native set, but not RF_MarkAsNative + CLASS_Native = 0x00000080, + /// Don't export to C++ header. + CLASS_NoExport = 0x00000100, + /// Do not allow users to create in the editor. + CLASS_NotPlaceable = 0x00000200, + /// Handle object configuration on a per-object basis, rather than per-class. + CLASS_PerObjectConfig = 0x00000400, + /// Whether SetUpRuntimeReplicationData still needs to be called for this class + CLASS_ReplicationDataIsSetUp = 0x00000800u, + /// Class can be constructed from editinline New button. + CLASS_EditInlineNew = 0x00001000, + /// Display properties in the editor without using categories. + CLASS_CollapseCategories = 0x00002000, + /// Class is an interface + CLASS_Interface = 0x00004000, + /// Do not export a constructor for this class, assuming it is in the cpptext + CLASS_CustomConstructor = 0x00008000, + /// All properties and functions in this class are const and should be exported as const + CLASS_Const = 0x00010000, + /// Class flag indicating the class is having its layout changed, and therefore is not ready for a CDO to be created + CLASS_LayoutChanging = 0x00020000, + /// Indicates that the class was created from blueprint source material + CLASS_CompiledFromBlueprint = 0x00040000, + /// Indicates that only the bare minimum bits of this class should be DLL exported/imported + CLASS_MinimalAPI = 0x00080000, + /// Indicates this class must be DLL exported/imported (along with all of it's members) + CLASS_RequiredAPI = 0x00100000, + /// Indicates that references to this class default to instanced. Used to be subclasses of UComponent, but now can be any UObject + CLASS_DefaultToInstanced = 0x00200000, + /// Indicates that the parent token stream has been merged with ours. + CLASS_TokenStreamAssembled = 0x00400000, + /// Class has component properties. + CLASS_HasInstancedReference = 0x00800000, + /// Don't show this class in the editor class browser or edit inline new menus. + CLASS_Hidden = 0x01000000, + /// Don't save objects of this class when serializing + CLASS_Deprecated = 0x02000000, + /// Class not shown in editor drop down for class selection + CLASS_HideDropDown = 0x04000000, + /// Class settings are saved to AppData/..../Blah.ini (as opposed to CLASS_DefaultConfig) + CLASS_GlobalUserConfig = 0x08000000, + /// Class was declared directly in C++ and has no boilerplate generated by UnrealHeaderTool + CLASS_Intrinsic = 0x10000000, + /// Class has already been constructed (maybe in a previous DLL version before hot-reload). + CLASS_Constructed = 0x20000000, + /// Indicates that object configuration will not check against ini base/defaults when serialized + CLASS_ConfigDoNotCheckDefaults = 0x40000000, + /// Class has been consigned to oblivion as part of a blueprint recompile, and a newer version currently exists. + CLASS_NewerVersionExists = 0x80000000, + }; + + /// + /// Flags describing a function. + /// + [Flags] + public enum EFunctionFlags : uint { + FUNC_None = 0x00000000, + FUNC_Final = 0x00000001, + FUNC_RequiredAPI = 0x00000002, + FUNC_BlueprintAuthorityOnly = 0x00000004, + FUNC_BlueprintCosmetic = 0x00000008, + FUNC_Net = 0x00000040, + FUNC_NetReliable = 0x00000080, + FUNC_NetRequest = 0x00000100, + FUNC_Exec = 0x00000200, + FUNC_Native = 0x00000400, + FUNC_Event = 0x00000800, + FUNC_NetResponse = 0x00001000, + FUNC_Static = 0x00002000, + FUNC_NetMulticast = 0x00004000, + FUNC_UbergraphFunction = 0x00008000, + FUNC_MulticastDelegate = 0x00010000, + FUNC_Public = 0x00020000, + FUNC_Private = 0x00040000, + FUNC_Protected = 0x00080000, + FUNC_Delegate = 0x00100000, + FUNC_NetServer = 0x00200000, + FUNC_HasOutParms = 0x00400000, + FUNC_HasDefaults = 0x00800000, + FUNC_NetClient = 0x01000000, + FUNC_DLLImport = 0x02000000, + FUNC_BlueprintCallable = 0x04000000, + FUNC_BlueprintEvent = 0x08000000, + FUNC_BlueprintPure = 0x10000000, + FUNC_EditorOnly = 0x20000000, + FUNC_Const = 0x40000000, + FUNC_NetValidate = 0x80000000, + FUNC_AllFlags = 0xFFFFFFFF, + }; +} diff --git a/Translation/UAssetAPI/UnrealTypes/TMap.cs b/Translation/UAssetAPI/UnrealTypes/TMap.cs new file mode 100644 index 0000000..47071dd --- /dev/null +++ b/Translation/UAssetAPI/UnrealTypes/TMap.cs @@ -0,0 +1,795 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Collections.Specialized; +using System.Linq; + +/* + The code in this file is modified from mattmc3's dotmore @ https://github.com/mattmc3/dotmore/tree/b032bbf871d46bffd698c9b7a233c533d9d2f0ebs for usage in UAssetAPI. + + The MIT License (MIT) + + Copyright (c) 2014 mattmc3 + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +*/ +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.UnrealTypes +{ + internal static class StringExtensions + { + /// + /// Provides a more natural way to call String.Format() on a string. + /// + /// The string to format. + /// An object array that contains zero or more objects to format + public static string FormatWith(this string s, params object[] args) + { + if (s == null) return null; + return string.Format(s, args); + } + + /// + /// Provides a more natural way to call String.Format() on a string. + /// + /// The string to format. + /// An object that supplies the culture specific formatting + /// An object array that contains zero or more objects to format + public static string FormatWith(this string s, IFormatProvider provider, params object[] args) + { + if (s == null) return null; + return string.Format(provider, s, args); + } + } + + public class DictionaryEnumerator : IDictionaryEnumerator, IDisposable + { + readonly IEnumerator> _impl; + public void Dispose() { _impl.Dispose(); } + public DictionaryEnumerator(IDictionary value) + { + this._impl = value.GetEnumerator(); + } + public void Reset() { _impl.Reset(); } + public bool MoveNext() { return _impl.MoveNext(); } + public DictionaryEntry Entry + { + get + { + var pair = _impl.Current; + return new DictionaryEntry(pair.Key, pair.Value); + } + } + public object Key { get { return _impl.Current.Key; } } + public object Value { get { return _impl.Current.Value; } } + public object Current { get { return Entry; } } + } + + public class Comparer2 : Comparer + { + private readonly Comparison _compareFunction; + + public Comparer2(Comparison comparison) + { + if (comparison == null) throw new ArgumentNullException("comparison"); + _compareFunction = comparison; + } + + public override int Compare(T arg1, T arg2) + { + return _compareFunction(arg1, arg2); + } + } + + /// + /// A concrete implementation of the abstract KeyedCollection class using lambdas for the + /// implementation. + /// + public class KeyedCollection2 : KeyedCollection + { + private const string DelegateNullExceptionMessage = "Delegate passed cannot be null"; + private Func _getKeyForItemFunction; + + public KeyedCollection2(Func getKeyForItemFunction) : base() + { + if (getKeyForItemFunction == null) throw new ArgumentNullException(DelegateNullExceptionMessage); + _getKeyForItemFunction = getKeyForItemFunction; + } + + public KeyedCollection2(Func getKeyForItemDelegate, IEqualityComparer comparer) : base(comparer) + { + if (getKeyForItemDelegate == null) throw new ArgumentNullException(DelegateNullExceptionMessage); + _getKeyForItemFunction = getKeyForItemDelegate; + } + + protected override TKey GetKeyForItem(TItem item) + { + return _getKeyForItemFunction(item); + } + + public void SortByKeys() + { + var comparer = Comparer.Default; + SortByKeys(comparer); + } + + public void SortByKeys(IComparer keyComparer) + { + var comparer = new Comparer2((x, y) => keyComparer.Compare(GetKeyForItem(x), GetKeyForItem(y))); + Sort(comparer); + } + + public void SortByKeys(Comparison keyComparison) + { + var comparer = new Comparer2((x, y) => keyComparison(GetKeyForItem(x), GetKeyForItem(y))); + Sort(comparer); + } + + public void Sort() + { + var comparer = Comparer.Default; + Sort(comparer); + } + + public void Sort(Comparison comparison) + { + var newComparer = new Comparer2((x, y) => comparison(x, y)); + Sort(newComparer); + } + + public void Sort(IComparer comparer) + { + List list = base.Items as List; + if (list != null) + { + list.Sort(comparer); + } + } + } + + public interface IOrderedDictionary : IDictionary, IOrderedDictionary + { + new TValue this[int index] { get; set; } + new TValue this[TKey key] { get; set; } + new int Count { get; } + new ICollection Keys { get; } + new ICollection Values { get; } + new void Add(TKey key, TValue value); + new void Clear(); + void Insert(int index, TKey key, TValue value); + int IndexOf(TKey key); + bool ContainsValue(TValue value); + bool ContainsValue(TValue value, IEqualityComparer comparer); + new bool ContainsKey(TKey key); + new IEnumerator> GetEnumerator(); + new bool Remove(TKey key); + new void RemoveAt(int index); + new bool TryGetValue(TKey key, out TValue value); + TValue GetValue(TKey key); + void SetValue(TKey key, TValue value); + KeyValuePair GetItem(int index); + void SetItem(int index, TValue value); + } + + /// + /// A dictionary object that allows rapid hash lookups using keys, but also + /// maintains the key insertion order so that values can be retrieved by + /// key index. + /// + public class TMap : IOrderedDictionary + { + #region Fields/Properties + + private KeyedCollection2> _keyedCollection; + + /// + /// Gets or sets the value associated with the specified key. + /// + /// The key associated with the value to get or set. + public TValue this[TKey key] + { + get + { + return GetValue(key); + } + set + { + SetValue(key, value); + } + } + + /// + /// Gets or sets the value at the specified index. + /// + /// The index of the value to get or set. + public TValue this[int index] + { + get + { + return GetItem(index).Value; + } + set + { + SetItem(index, value); + } + } + + /// + /// Gets the number of items in the dictionary + /// + public int Count + { + get { return _keyedCollection.Count; } + } + + /// + /// Gets all the keys in the ordered dictionary in their proper order. + /// + public ICollection Keys + { + get + { + return _keyedCollection.Select(x => x.Key).ToList(); + } + } + + /// + /// Gets all the values in the ordered dictionary in their proper order. + /// + public ICollection Values + { + get + { + return _keyedCollection.Select(x => x.Value).ToList(); + } + } + + /// + /// Gets the key comparer for this dictionary + /// + public IEqualityComparer Comparer + { + get; + private set; + } + + #endregion + + #region Constructors + + public TMap() + { + Initialize(); + } + + public TMap(IEqualityComparer comparer) + { + Initialize(comparer); + } + + public TMap(IOrderedDictionary dictionary) + { + Initialize(); + foreach (KeyValuePair pair in dictionary) + { + _keyedCollection.Add(pair); + } + } + + public TMap(IOrderedDictionary dictionary, IEqualityComparer comparer) + { + Initialize(comparer); + foreach (KeyValuePair pair in dictionary) + { + _keyedCollection.Add(pair); + } + } + + public TMap(IEnumerable> items) + { + Initialize(); + foreach (KeyValuePair pair in items) + { + _keyedCollection.Add(pair); + } + } + + public TMap(IEnumerable> items, IEqualityComparer comparer) + { + Initialize(comparer); + foreach (KeyValuePair pair in items) + { + _keyedCollection.Add(pair); + } + } + + #endregion + + #region Methods + + private void Initialize(IEqualityComparer comparer = null) + { + this.Comparer = comparer; + if (comparer != null) + { + _keyedCollection = new KeyedCollection2>(x => x.Key, comparer); + } + else + { + _keyedCollection = new KeyedCollection2>(x => x.Key); + } + } + + /// + /// Adds the specified key and value to the dictionary. + /// + /// The key of the element to add. + /// The value of the element to add. The value can be null for reference types. + public void Add(TKey key, TValue value) + { + _keyedCollection.Add(new KeyValuePair(key, value)); + } + + /// + /// Removes all keys and values from this object. + /// + public void Clear() + { + _keyedCollection.Clear(); + } + + /// + /// Inserts a new key-value pair at the index specified. + /// + /// The insertion index. This value must be between 0 and the count of items in this object. + /// A unique key for the element to add + /// The value of the element to add. Can be null for reference types. + public void Insert(int index, TKey key, TValue value) + { + _keyedCollection.Insert(index, new KeyValuePair(key, value)); + } + + /// + /// Gets the index of the key specified. + /// + /// The key whose index will be located + /// Returns the index of the key specified if found. Returns -1 if the key could not be located. + public int IndexOf(TKey key) + { + if (_keyedCollection.Contains(key)) + { + return _keyedCollection.IndexOf(_keyedCollection[key]); + } + else + { + return -1; + } + } + + /// + /// Determines whether this object contains the specified value. + /// + /// The value to locate in this object. + /// True if the value is found. False otherwise. + public bool ContainsValue(TValue value) + { + return this.Values.Contains(value); + } + + /// + /// Determines whether this object contains the specified value. + /// + /// The value to locate in this object. + /// The equality comparer used to locate the specified value in this object. + /// True if the value is found. False otherwise. + public bool ContainsValue(TValue value, IEqualityComparer comparer) + { + return this.Values.Contains(value, comparer); + } + + /// + /// Determines whether this object contains the specified key. + /// + /// The key to locate in this object. + /// True if the key is found. False otherwise. + public bool ContainsKey(TKey key) + { + return _keyedCollection.Contains(key); + } + + /// + /// Returns the KeyValuePair at the index specified. + /// + /// The index of the KeyValuePair desired + /// + /// Thrown when the index specified does not refer to a KeyValuePair in this object + /// + public KeyValuePair GetItem(int index) + { + if (index < 0 || index >= _keyedCollection.Count) + { + throw new ArgumentException("The index was outside the bounds of the dictionary: {0}".FormatWith(index)); + } + return _keyedCollection[index]; + } + + /// + /// Sets the value at the index specified. + /// + /// The index of the value desired + /// The value to set + /// + /// Thrown when the index specified does not refer to a KeyValuePair in this object + /// + public void SetItem(int index, TValue value) + { + if (index < 0 || index >= _keyedCollection.Count) + { + throw new ArgumentException("The index is outside the bounds of the dictionary: {0}".FormatWith(index)); + } + var kvp = new KeyValuePair(_keyedCollection[index].Key, value); + _keyedCollection[index] = kvp; + } + + /// + /// Returns an enumerator that iterates through all the KeyValuePairs in this object. + /// + public IEnumerator> GetEnumerator() + { + return _keyedCollection.GetEnumerator(); + } + + /// + /// Removes the key-value pair for the specified key. + /// + /// The key to remove from the dictionary. + /// True if the item specified existed and the removal was successful. False otherwise. + public bool Remove(TKey key) + { + return _keyedCollection.Remove(key); + } + + /// + /// Removes the key-value pair at the specified index. + /// + /// The index of the key-value pair to remove from the dictionary. + public void RemoveAt(int index) + { + if (index < 0 || index >= _keyedCollection.Count) + { + throw new ArgumentException("The index was outside the bounds of the dictionary: {0}".FormatWith(index)); + } + _keyedCollection.RemoveAt(index); + } + + /// + /// Gets the value associated with the specified key. + /// + /// The key associated with the value to get. + public TValue GetValue(TKey key) + { + if (_keyedCollection.Contains(key) == false) + { + throw new ArgumentException("The given key is not present in the dictionary: {0}".FormatWith(key)); + } + var kvp = _keyedCollection[key]; + return kvp.Value; + } + + /// + /// Sets the value associated with the specified key. + /// + /// The key associated with the value to set. + /// The the value to set. + public void SetValue(TKey key, TValue value) + { + var kvp = new KeyValuePair(key, value); + var idx = IndexOf(key); + if (idx > -1) + { + _keyedCollection[idx] = kvp; + } + else + { + _keyedCollection.Add(kvp); + } + } + + /// + /// Tries to get the value associated with the specified key. + /// + /// The key of the desired element. + /// + /// When this method returns, contains the value associated with the specified key if + /// that key was found. Otherwise it will contain the default value for parameter's type. + /// This parameter should be provided uninitialized. + /// + /// True if the value was found. False otherwise. + /// + public bool TryGetValue(TKey key, out TValue value) + { + if (_keyedCollection.Contains(key)) + { + value = _keyedCollection[key].Value; + return true; + } + else + { + value = default(TValue); + return false; + } + } + + #endregion + + #region Sorting + public void SortKeys() + { + _keyedCollection.SortByKeys(); + } + + public void SortKeys(IComparer comparer) + { + _keyedCollection.SortByKeys(comparer); + } + + public void SortKeys(Comparison comparison) + { + _keyedCollection.SortByKeys(comparison); + } + + public void SortValues() + { + var comparer = Comparer.Default; + SortValues(comparer); + } + + public void SortValues(IComparer comparer) + { + _keyedCollection.Sort((x, y) => comparer.Compare(x.Value, y.Value)); + } + + public void SortValues(Comparison comparison) + { + _keyedCollection.Sort((x, y) => comparison(x.Value, y.Value)); + } + #endregion + + #region IDictionary + + void IDictionary.Add(TKey key, TValue value) + { + Add(key, value); + } + + bool IDictionary.ContainsKey(TKey key) + { + return ContainsKey(key); + } + + ICollection IDictionary.Keys + { + get { return Keys; } + } + + bool IDictionary.Remove(TKey key) + { + return Remove(key); + } + + bool IDictionary.TryGetValue(TKey key, out TValue value) + { + return TryGetValue(key, out value); + } + + ICollection IDictionary.Values + { + get { return Values; } + } + + TValue IDictionary.this[TKey key] + { + get + { + return this[key]; + } + set + { + this[key] = value; + } + } + + #endregion + + #region ICollection> + + void ICollection>.Add(KeyValuePair item) + { + _keyedCollection.Add(item); + } + + void ICollection>.Clear() + { + _keyedCollection.Clear(); + } + + bool ICollection>.Contains(KeyValuePair item) + { + return _keyedCollection.Contains(item); + } + + void ICollection>.CopyTo(KeyValuePair[] array, int arrayIndex) + { + _keyedCollection.CopyTo(array, arrayIndex); + } + + int ICollection>.Count + { + get { return _keyedCollection.Count; } + } + + bool ICollection>.IsReadOnly + { + get { return false; } + } + + bool ICollection>.Remove(KeyValuePair item) + { + return _keyedCollection.Remove(item); + } + + #endregion + + #region IEnumerable> + + IEnumerator> IEnumerable>.GetEnumerator() + { + return GetEnumerator(); + } + + #endregion + + #region IEnumerable + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + #endregion + + #region IOrderedDictionary + + IDictionaryEnumerator IOrderedDictionary.GetEnumerator() + { + return new DictionaryEnumerator(this); + } + + void IOrderedDictionary.Insert(int index, object key, object value) + { + Insert(index, (TKey)key, (TValue)value); + } + + void IOrderedDictionary.RemoveAt(int index) + { + RemoveAt(index); + } + + object IOrderedDictionary.this[int index] + { + get + { + return this[index]; + } + set + { + this[index] = (TValue)value; + } + } + + #endregion + + #region IDictionary + + void IDictionary.Add(object key, object value) + { + Add((TKey)key, (TValue)value); + } + + void IDictionary.Clear() + { + Clear(); + } + + bool IDictionary.Contains(object key) + { + return _keyedCollection.Contains((TKey)key); + } + + IDictionaryEnumerator IDictionary.GetEnumerator() + { + return new DictionaryEnumerator(this); + } + + bool IDictionary.IsFixedSize + { + get { return false; } + } + + bool IDictionary.IsReadOnly + { + get { return false; } + } + + ICollection IDictionary.Keys + { + get { return (ICollection)this.Keys; } + } + + void IDictionary.Remove(object key) + { + Remove((TKey)key); + } + + ICollection IDictionary.Values + { + get { return (ICollection)this.Values; } + } + + object IDictionary.this[object key] + { + get + { + return this[(TKey)key]; + } + set + { + this[(TKey)key] = (TValue)value; + } + } + + #endregion + + #region ICollection + + void ICollection.CopyTo(Array array, int index) + { + ((ICollection)_keyedCollection).CopyTo(array, index); + } + + int ICollection.Count + { + get { return ((ICollection)_keyedCollection).Count; } + } + + bool ICollection.IsSynchronized + { + get { return ((ICollection)_keyedCollection).IsSynchronized; } + } + + object ICollection.SyncRoot + { + get { return ((ICollection)_keyedCollection).SyncRoot; } + } + + #endregion + } +} \ No newline at end of file diff --git a/Translation/UAssetAPI/UnrealTypes/UE4Version.cs b/Translation/UAssetAPI/UnrealTypes/UE4Version.cs new file mode 100644 index 0000000..0a6dd7d --- /dev/null +++ b/Translation/UAssetAPI/UnrealTypes/UE4Version.cs @@ -0,0 +1,708 @@ +namespace UAssetAPI.UnrealTypes +{ + public enum UE4Version + { + UNKNOWN = 0, + VER_UE4_OLDEST_LOADABLE_PACKAGE = 214, + + /// Removed restriction on blueprint-exposed variables from being read-only + VER_UE4_BLUEPRINT_VARS_NOT_READ_ONLY, + /// Added manually serialized element to UStaticMesh (precalculated nav collision) + VER_UE4_STATIC_MESH_STORE_NAV_COLLISION, + /// Changed property name for atmospheric fog + VER_UE4_ATMOSPHERIC_FOG_DECAY_NAME_CHANGE, + /// Change many properties/functions from Translation to Location + VER_UE4_SCENECOMP_TRANSLATION_TO_LOCATION, + /// Material attributes reordering + VER_UE4_MATERIAL_ATTRIBUTES_REORDERING, + /// Collision Profile setting has been added, and all components that exists has to be properly upgraded + VER_UE4_COLLISION_PROFILE_SETTING, + /// Making the blueprint's skeleton class transient + VER_UE4_BLUEPRINT_SKEL_TEMPORARY_TRANSIENT, + /// Making the blueprint's skeleton class serialized again + VER_UE4_BLUEPRINT_SKEL_SERIALIZED_AGAIN, + /// Blueprint now controls replication settings again + VER_UE4_BLUEPRINT_SETS_REPLICATION, + /// Added level info used by World browser + VER_UE4_WORLD_LEVEL_INFO, + /// Changed capsule height to capsule half-height (afterwards) + VER_UE4_AFTER_CAPSULE_HALF_HEIGHT_CHANGE, + /// Added Namepace, GUID (Key) and Flags to FText + VER_UE4_ADDED_NAMESPACE_AND_KEY_DATA_TO_FTEXT, + /// Attenuation shapes + VER_UE4_ATTENUATION_SHAPES, + /// Use IES texture multiplier even when IES brightness is not being used + VER_UE4_LIGHTCOMPONENT_USE_IES_TEXTURE_MULTIPLIER_ON_NON_IES_BRIGHTNESS, + /// Removed InputComponent as a blueprint addable component + VER_UE4_REMOVE_INPUT_COMPONENTS_FROM_BLUEPRINTS, + /// Use an FMemberReference struct in UK2Node_Variable + VER_UE4_VARK2NODE_USE_MEMBERREFSTRUCT, + /// Refactored material expression inputs for UMaterialExpressionSceneColor and UMaterialExpressionSceneDepth + VER_UE4_REFACTOR_MATERIAL_EXPRESSION_SCENECOLOR_AND_SCENEDEPTH_INPUTS, + /// Spline meshes changed from Z forwards to configurable + VER_UE4_SPLINE_MESH_ORIENTATION, + /// Added ReverbEffect asset type + VER_UE4_REVERB_EFFECT_ASSET_TYPE, + /// changed max texcoords from 4 to 8 + VER_UE4_MAX_TEXCOORD_INCREASED, + /// static meshes changed to support SpeedTrees + VER_UE4_SPEEDTREE_STATICMESH, + /// Landscape component reference between landscape component and collision component + VER_UE4_LANDSCAPE_COMPONENT_LAZY_REFERENCES, + /// Refactored UK2Node_CallFunction to use FMemberReference + VER_UE4_SWITCH_CALL_NODE_TO_USE_MEMBER_REFERENCE, + /// Added fixup step to remove skeleton class references from blueprint objects + VER_UE4_ADDED_SKELETON_ARCHIVER_REMOVAL, + /// See above, take 2. + VER_UE4_ADDED_SKELETON_ARCHIVER_REMOVAL_SECOND_TIME, + /// Making the skeleton class on blueprints transient + VER_UE4_BLUEPRINT_SKEL_CLASS_TRANSIENT_AGAIN, + /// UClass knows if it's been cooked + VER_UE4_ADD_COOKED_TO_UCLASS, + /// Deprecated static mesh thumbnail properties were removed + VER_UE4_DEPRECATED_STATIC_MESH_THUMBNAIL_PROPERTIES_REMOVED, + /// Added collections in material shader map ids + VER_UE4_COLLECTIONS_IN_SHADERMAPID, + /// Renamed some Movement Component properties, added PawnMovementComponent + VER_UE4_REFACTOR_MOVEMENT_COMPONENT_HIERARCHY, + /// Swap UMaterialExpressionTerrainLayerSwitch::LayerUsed/LayerNotUsed the correct way round + VER_UE4_FIX_TERRAIN_LAYER_SWITCH_ORDER, + /// Remove URB_ConstraintSetup + VER_UE4_ALL_PROPS_TO_CONSTRAINTINSTANCE, + /// Low quality directional lightmaps + VER_UE4_LOW_QUALITY_DIRECTIONAL_LIGHTMAPS, + /// Added NoiseEmitterComponent and removed related Pawn properties. + VER_UE4_ADDED_NOISE_EMITTER_COMPONENT, + /// Add text component vertical alignment + VER_UE4_ADD_TEXT_COMPONENT_VERTICAL_ALIGNMENT, + /// Added AssetImportData for FBX asset types, deprecating SourceFilePath and SourceFileTimestamp + VER_UE4_ADDED_FBX_ASSET_IMPORT_DATA, + /// Remove LevelBodySetup from ULevel + VER_UE4_REMOVE_LEVELBODYSETUP, + /// Refactor character crouching + VER_UE4_REFACTOR_CHARACTER_CROUCH, + /// Trimmed down material shader debug information. + VER_UE4_SMALLER_DEBUG_MATERIALSHADER_UNIFORM_EXPRESSIONS, + /// APEX Clothing + VER_UE4_APEX_CLOTH, + /// + /// Change Collision Channel to save only modified ones than all of them. + /// Note!!! Once we pass this CL, we can rename FCollisionResponseContainer enum values. + /// We should rename to match ECollisionChannel + /// + VER_UE4_SAVE_COLLISIONRESPONSE_PER_CHANNEL, + /// Added Landscape Spline editor meshes + VER_UE4_ADDED_LANDSCAPE_SPLINE_EDITOR_MESH, + /// Fixup input expressions for reading from refraction material attributes. + VER_UE4_CHANGED_MATERIAL_REFACTION_TYPE, + /// Refactor projectile movement, along with some other movement component work. + VER_UE4_REFACTOR_PROJECTILE_MOVEMENT, + /// Remove PhysicalMaterialProperty and replace with user defined enum + VER_UE4_REMOVE_PHYSICALMATERIALPROPERTY, + /// Removed all compile outputs from FMaterial + VER_UE4_PURGED_FMATERIAL_COMPILE_OUTPUTS, + /// Ability to save cooked PhysX meshes to Landscape + VER_UE4_ADD_COOKED_TO_LANDSCAPE, + /// Change how input component consumption works + VER_UE4_CONSUME_INPUT_PER_BIND, + /// Added new Graph based SoundClass Editor + VER_UE4_SOUND_CLASS_GRAPH_EDITOR, + /// Fixed terrain layer node guids which was causing artifacts + VER_UE4_FIXUP_TERRAIN_LAYER_NODES, + /// Added clamp min/max swap check to catch older materials + VER_UE4_RETROFIT_CLAMP_EXPRESSIONS_SWAP, + /// Remove static/movable/stationary light classes + VER_UE4_REMOVE_LIGHT_MOBILITY_CLASSES, + /// Refactor the way physics blending works to allow partial blending + VER_UE4_REFACTOR_PHYSICS_BLENDING, + /// WorldLevelInfo: Added reference to parent level and streaming distance + VER_UE4_WORLD_LEVEL_INFO_UPDATED, + /// Fixed cooking of skeletal/static meshes due to bad serialization logic + VER_UE4_STATIC_SKELETAL_MESH_SERIALIZATION_FIX, + /// Removal of InterpActor and PhysicsActor + VER_UE4_REMOVE_STATICMESH_MOBILITY_CLASSES, + /// Refactor physics transforms + VER_UE4_REFACTOR_PHYSICS_TRANSFORMS, + /// Remove zero triangle sections from static meshes and compact material indices. + VER_UE4_REMOVE_ZERO_TRIANGLE_SECTIONS, + /// Add param for deceleration in character movement instead of using acceleration. + VER_UE4_CHARACTER_MOVEMENT_DECELERATION, + /// Made ACameraActor use a UCameraComponent for parameter storage, etc... + VER_UE4_CAMERA_ACTOR_USING_CAMERA_COMPONENT, + /// Deprecated some pitch/roll properties in CharacterMovementComponent + VER_UE4_CHARACTER_MOVEMENT_DEPRECATE_PITCH_ROLL, + /// Rebuild texture streaming data on load for uncooked builds + VER_UE4_REBUILD_TEXTURE_STREAMING_DATA_ON_LOAD, + /// Add support for 32 bit index buffers for static meshes. + VER_UE4_SUPPORT_32BIT_STATIC_MESH_INDICES, + /// Added streaming install ChunkID to AssetData and UPackage + VER_UE4_ADDED_CHUNKID_TO_ASSETDATA_AND_UPACKAGE, + /// Add flag to control whether Character blueprints receive default movement bindings. + VER_UE4_CHARACTER_DEFAULT_MOVEMENT_BINDINGS, + /// APEX Clothing LOD Info + VER_UE4_APEX_CLOTH_LOD, + /// Added atmospheric fog texture data to be general + VER_UE4_ATMOSPHERIC_FOG_CACHE_DATA, + /// Arrays serialize their inner's tags + VAR_UE4_ARRAY_PROPERTY_INNER_TAGS, + /// Skeletal mesh index data is kept in memory in game to support mesh merging. + VER_UE4_KEEP_SKEL_MESH_INDEX_DATA, + /// Added compatibility for the body instance collision change + VER_UE4_BODYSETUP_COLLISION_CONVERSION, + /// Reflection capture cooking + VER_UE4_REFLECTION_CAPTURE_COOKING, + /// Removal of DynamicTriggerVolume, DynamicBlockingVolume, DynamicPhysicsVolume + VER_UE4_REMOVE_DYNAMIC_VOLUME_CLASSES, + /// Store an additional flag in the BodySetup to indicate whether there is any cooked data to load + VER_UE4_STORE_HASCOOKEDDATA_FOR_BODYSETUP, + /// Changed name of RefractionBias to RefractionDepthBias. + VER_UE4_REFRACTION_BIAS_TO_REFRACTION_DEPTH_BIAS, + /// Removal of SkeletalPhysicsActor + VER_UE4_REMOVE_SKELETALPHYSICSACTOR, + /// PlayerController rotation input refactor + VER_UE4_PC_ROTATION_INPUT_REFACTOR, + /// Landscape Platform Data cooking + VER_UE4_LANDSCAPE_PLATFORMDATA_COOKING, + /// Added call for linking classes in CreateExport to ensure memory is initialized properly + VER_UE4_CREATEEXPORTS_CLASS_LINKING_FOR_BLUEPRINTS, + /// Remove native component nodes from the blueprint SimpleConstructionScript + VER_UE4_REMOVE_NATIVE_COMPONENTS_FROM_BLUEPRINT_SCS, + /// Removal of Single Node Instance + VER_UE4_REMOVE_SINGLENODEINSTANCE, + /// Character movement braking changes + VER_UE4_CHARACTER_BRAKING_REFACTOR, + /// Supported low quality lightmaps in volume samples + VER_UE4_VOLUME_SAMPLE_LOW_QUALITY_SUPPORT, + /// Split bEnableTouchEvents out from bEnableClickEvents + VER_UE4_SPLIT_TOUCH_AND_CLICK_ENABLES, + /// Health/Death refactor + VER_UE4_HEALTH_DEATH_REFACTOR, + /// Moving USoundNodeEnveloper from UDistributionFloatConstantCurve to FRichCurve + VER_UE4_SOUND_NODE_ENVELOPER_CURVE_CHANGE, + /// Moved SourceRadius to UPointLightComponent + VER_UE4_POINT_LIGHT_SOURCE_RADIUS, + /// Scene capture actors based on camera actors. + VER_UE4_SCENE_CAPTURE_CAMERA_CHANGE, + /// Moving SkeletalMesh shadow casting flag from LoD details to material + VER_UE4_MOVE_SKELETALMESH_SHADOWCASTING, + /// Changing bytecode operators for creating arrays + VER_UE4_CHANGE_SETARRAY_BYTECODE, + /// Material Instances overriding base material properties. + VER_UE4_MATERIAL_INSTANCE_BASE_PROPERTY_OVERRIDES, + /// Combined top/bottom lightmap textures + VER_UE4_COMBINED_LIGHTMAP_TEXTURES, + /// Forced material lightmass guids to be regenerated + VER_UE4_BUMPED_MATERIAL_EXPORT_GUIDS, + /// Allow overriding of parent class input bindings + VER_UE4_BLUEPRINT_INPUT_BINDING_OVERRIDES, + /// Fix up convex invalid transform + VER_UE4_FIXUP_BODYSETUP_INVALID_CONVEX_TRANSFORM, + /// Fix up scale of physics stiffness and damping value + VER_UE4_FIXUP_STIFFNESS_AND_DAMPING_SCALE, + /// Convert USkeleton and FBoneContrainer to using FReferenceSkeleton. + VER_UE4_REFERENCE_SKELETON_REFACTOR, + /// Adding references to variable, function, and macro nodes to be able to update to renamed values + VER_UE4_K2NODE_REFERENCEGUIDS, + /// Fix up the 0th bone's parent bone index. + VER_UE4_FIXUP_ROOTBONE_PARENT, + //Allow setting of TextRenderComponents size in world space. + VER_UE4_TEXT_RENDER_COMPONENTS_WORLD_SPACE_SIZING, + /// Material Instances overriding base material properties #2. + VER_UE4_MATERIAL_INSTANCE_BASE_PROPERTY_OVERRIDES_PHASE_2, + /// CLASS_Placeable becomes CLASS_NotPlaceable + VER_UE4_CLASS_NOTPLACEABLE_ADDED, + /// Added LOD info list to a world tile description + VER_UE4_WORLD_LEVEL_INFO_LOD_LIST, + /// CharacterMovement variable naming refactor + VER_UE4_CHARACTER_MOVEMENT_VARIABLE_RENAMING_1, + /// FName properties containing sound names converted to FSlateSound properties + VER_UE4_FSLATESOUND_CONVERSION, + /// Added ZOrder to a world tile description + VER_UE4_WORLD_LEVEL_INFO_ZORDER, + /// Added flagging of localization gather requirement to packages + VER_UE4_PACKAGE_REQUIRES_LOCALIZATION_GATHER_FLAGGING, + /// Preventing Blueprint Actor variables from having default values + VER_UE4_BP_ACTOR_VARIABLE_DEFAULT_PREVENTING, + /// Preventing Blueprint Actor variables from having default values + VER_UE4_TEST_ANIMCOMP_CHANGE, + /// Class as primary asset, name convention changed + VER_UE4_EDITORONLY_BLUEPRINTS, + /// Custom serialization for FEdGraphPinType + VER_UE4_EDGRAPHPINTYPE_SERIALIZATION, + /// Stop generating 'mirrored' cooked mesh for Brush and Model components + VER_UE4_NO_MIRROR_BRUSH_MODEL_COLLISION, + /// Changed ChunkID to be an array of IDs. + VER_UE4_CHANGED_CHUNKID_TO_BE_AN_ARRAY_OF_CHUNKIDS, + /// Worlds have been renamed from "TheWorld" to be named after the package containing them + VER_UE4_WORLD_NAMED_AFTER_PACKAGE, + /// Added sky light component + VER_UE4_SKY_LIGHT_COMPONENT, + /// Added Enable distance streaming flag to FWorldTileLayer + VER_UE4_WORLD_LAYER_ENABLE_DISTANCE_STREAMING, + /// Remove visibility/zone information from UModel + VER_UE4_REMOVE_ZONES_FROM_MODEL, + /// Fix base pose serialization + VER_UE4_FIX_ANIMATIONBASEPOSE_SERIALIZATION, + /// Support for up to 8 skinning influences per vertex on skeletal meshes (on non-gpu vertices) + VER_UE4_SUPPORT_8_BONE_INFLUENCES_SKELETAL_MESHES, + /// Add explicit bOverrideGravity to world settings + VER_UE4_ADD_OVERRIDE_GRAVITY_FLAG, + /// Support for up to 8 skinning influences per vertex on skeletal meshes (on gpu vertices) + VER_UE4_SUPPORT_GPUSKINNING_8_BONE_INFLUENCES, + /// Supporting nonuniform scale animation + VER_UE4_ANIM_SUPPORT_NONUNIFORM_SCALE_ANIMATION, + /// Engine version is stored as a FEngineVersion object rather than changelist number + VER_UE4_ENGINE_VERSION_OBJECT, + /// World assets now have RF_Public + VER_UE4_PUBLIC_WORLDS, + /// Skeleton Guid + VER_UE4_SKELETON_GUID_SERIALIZATION, + /// Character movement WalkableFloor refactor + VER_UE4_CHARACTER_MOVEMENT_WALKABLE_FLOOR_REFACTOR, + /// Lights default to inverse squared + VER_UE4_INVERSE_SQUARED_LIGHTS_DEFAULT, + /// Disabled SCRIPT_LIMIT_BYTECODE_TO_64KB + VER_UE4_DISABLED_SCRIPT_LIMIT_BYTECODE, + /// Made remote role private, exposed bReplicates + VER_UE4_PRIVATE_REMOTE_ROLE, + /// Fix up old foliage components to have static mobility (superseded by VER_UE4_FOLIAGE_MOVABLE_MOBILITY) + VER_UE4_FOLIAGE_STATIC_MOBILITY, + /// Change BuildScale from a float to a vector + VER_UE4_BUILD_SCALE_VECTOR, + /// After implementing foliage collision, need to disable collision on old foliage instances + VER_UE4_FOLIAGE_COLLISION, + /// Added sky bent normal to indirect lighting cache + VER_UE4_SKY_BENT_NORMAL, + /// Added cooking for landscape collision data + VER_UE4_LANDSCAPE_COLLISION_DATA_COOKING, + /// + /// Convert CPU tangent Z delta to vector from PackedNormal since we don't get any benefit other than memory + /// we still convert all to FVector in CPU time whenever any calculation + /// + VER_UE4_MORPHTARGET_CPU_TANGENTZDELTA_FORMATCHANGE, + /// Soft constraint limits will implicitly use the mass of the bodies + VER_UE4_SOFT_CONSTRAINTS_USE_MASS, + /// Reflection capture data saved in packages + VER_UE4_REFLECTION_DATA_IN_PACKAGES, + /// Fix up old foliage components to have movable mobility (superseded by VER_UE4_FOLIAGE_STATIC_LIGHTING_SUPPORT) + VER_UE4_FOLIAGE_MOVABLE_MOBILITY, + /// Undo BreakMaterialAttributes changes as it broke old content + VER_UE4_UNDO_BREAK_MATERIALATTRIBUTES_CHANGE, + /// Now Default custom profile name isn't NONE anymore due to copy/paste not working properly with it + VER_UE4_ADD_CUSTOMPROFILENAME_CHANGE, + /// Permanently flip and scale material expression coordinates + VER_UE4_FLIP_MATERIAL_COORDS, + /// PinSubCategoryMemberReference added to FEdGraphPinType + VER_UE4_MEMBERREFERENCE_IN_PINTYPE, + /// Vehicles use Nm for Torque instead of cm and RPM instead of rad/s + VER_UE4_VEHICLES_UNIT_CHANGE, + /// + /// removes NANs from all animations when loaded + /// now importing should detect NaNs, so we should not have NaNs in source data + /// + VER_UE4_ANIMATION_REMOVE_NANS, + /// Change skeleton preview attached assets property type + VER_UE4_SKELETON_ASSET_PROPERTY_TYPE_CHANGE, + /// + /// Fix some blueprint variables that have the CPF_DisableEditOnTemplate flag set + /// when they shouldn't + /// + VER_UE4_FIX_BLUEPRINT_VARIABLE_FLAGS, + /// Vehicles use Nm for Torque instead of cm and RPM instead of rad/s part two (missed conversion for some variables + VER_UE4_VEHICLES_UNIT_CHANGE2, + /// Changed order of interface class serialization + VER_UE4_UCLASS_SERIALIZE_INTERFACES_AFTER_LINKING, + /// Change from LOD distances to display factors + VER_UE4_STATIC_MESH_SCREEN_SIZE_LODS, + /// Requires test of material coords to ensure they're saved correctly + VER_UE4_FIX_MATERIAL_COORDS, + /// Changed SpeedTree wind presets to v7 + VER_UE4_SPEEDTREE_WIND_V7, + /// NeedsLoadForEditorGame added + VER_UE4_LOAD_FOR_EDITOR_GAME, + /// Manual serialization of FRichCurveKey to save space + VER_UE4_SERIALIZE_RICH_CURVE_KEY, + /// Change the outer of ULandscapeMaterialInstanceConstants and Landscape-related textures to the level in which they reside + VER_UE4_MOVE_LANDSCAPE_MICS_AND_TEXTURES_WITHIN_LEVEL, + /// FTexts have creation history data, removed Key, Namespaces, and SourceString + VER_UE4_FTEXT_HISTORY, + /// Shift comments to the left to contain expressions properly + VER_UE4_FIX_MATERIAL_COMMENTS, + /// Bone names stored as FName means that we can't guarantee the correct case on export, now we store a separate string for export purposes only + VER_UE4_STORE_BONE_EXPORT_NAMES, + /// changed mesh emitter initial orientation to distribution + VER_UE4_MESH_EMITTER_INITIAL_ORIENTATION_DISTRIBUTION, + /// Foliage on blueprints causes crashes + VER_UE4_DISALLOW_FOLIAGE_ON_BLUEPRINTS, + /// change motors to use revolutions per second instead of rads/second + VER_UE4_FIXUP_MOTOR_UNITS, + /// deprecated MovementComponent functions including "ModifiedMaxSpeed" et al + VER_UE4_DEPRECATED_MOVEMENTCOMPONENT_MODIFIED_SPEEDS, + /// rename CanBeCharacterBase + VER_UE4_RENAME_CANBECHARACTERBASE, + /// Change GameplayTagContainers to have FGameplayTags instead of FNames; Required to fix-up native serialization + VER_UE4_GAMEPLAY_TAG_CONTAINER_TAG_TYPE_CHANGE, + /// Change from UInstancedFoliageSettings to UFoliageType, and change the api from being keyed on UStaticMesh* to UFoliageType* + VER_UE4_FOLIAGE_SETTINGS_TYPE, + /// Lights serialize static shadow depth maps + VER_UE4_STATIC_SHADOW_DEPTH_MAPS, + /// Add RF_Transactional to data assets, fixing undo problems when editing them + VER_UE4_ADD_TRANSACTIONAL_TO_DATA_ASSETS, + /// Change LB_AlphaBlend to LB_WeightBlend in ELandscapeLayerBlendType + VER_UE4_ADD_LB_WEIGHTBLEND, + /// Add root component to an foliage actor, all foliage cluster components will be attached to a root + VER_UE4_ADD_ROOTCOMPONENT_TO_FOLIAGEACTOR, + /// FMaterialInstanceBasePropertyOverrides didn't use proper UObject serialize + VER_UE4_FIX_MATERIAL_PROPERTY_OVERRIDE_SERIALIZE, + /// Addition of linear color sampler. color sample type is changed to linear sampler if source texture !sRGB + VER_UE4_ADD_LINEAR_COLOR_SAMPLER, + /// Added StringAssetReferencesMap to support renames of FStringAssetReference properties. + VER_UE4_ADD_STRING_ASSET_REFERENCES_MAP, + /// Apply scale from SCS RootComponent details in the Blueprint Editor to new actor instances at construction time + VER_UE4_BLUEPRINT_USE_SCS_ROOTCOMPONENT_SCALE, + /// Changed level streaming to have a linear color since the visualization doesn't gamma correct. + VER_UE4_LEVEL_STREAMING_DRAW_COLOR_TYPE_CHANGE, + /// Cleared end triggers from non-state anim notifies + VER_UE4_CLEAR_NOTIFY_TRIGGERS, + /// Convert old curve names stored in anim assets into skeleton smartnames + VER_UE4_SKELETON_ADD_SMARTNAMES, + /// Added the currency code field to FTextHistory_AsCurrency + VER_UE4_ADDED_CURRENCY_CODE_TO_FTEXT, + /// Added support for C++11 enum classes + VER_UE4_ENUM_CLASS_SUPPORT, + /// Fixup widget animation class + VER_UE4_FIXUP_WIDGET_ANIMATION_CLASS, + /// USoundWave objects now contain details about compression scheme used. + VER_UE4_SOUND_COMPRESSION_TYPE_ADDED, + /// Bodies will automatically weld when attached + VER_UE4_AUTO_WELDING, + /// Rename UCharacterMovementComponent::bCrouchMovesCharacterDown + VER_UE4_RENAME_CROUCHMOVESCHARACTERDOWN, + /// Lightmap parameters in FMeshBuildSettings + VER_UE4_LIGHTMAP_MESH_BUILD_SETTINGS, + /// Rename SM3 to ES3_1 and updates featurelevel material node selector + VER_UE4_RENAME_SM3_TO_ES3_1, + /// Deprecated separate style assets for use in UMG + VER_UE4_DEPRECATE_UMG_STYLE_ASSETS, + /// Duplicating Blueprints will regenerate NodeGuids after this version + VER_UE4_POST_DUPLICATE_NODE_GUID, + /// + /// Rename USpringArmComponent::bUseControllerViewRotation to bUsePawnViewRotation, + /// Rename UCameraComponent::bUseControllerViewRotation to bUsePawnViewRotation (and change the default value) + /// + VER_UE4_RENAME_CAMERA_COMPONENT_VIEW_ROTATION, + /// Changed FName to be case preserving + VER_UE4_CASE_PRESERVING_FNAME, + /// + /// Rename USpringArmComponent::bUsePawnViewRotation to bUsePawnControlRotation, + /// Rename UCameraComponent::bUsePawnViewRotation to bUsePawnControlRotation + /// + VER_UE4_RENAME_CAMERA_COMPONENT_CONTROL_ROTATION, + /// Fix bad refraction material attribute masks + VER_UE4_FIX_REFRACTION_INPUT_MASKING, + /// A global spawn rate for emitters. + VER_UE4_GLOBAL_EMITTER_SPAWN_RATE_SCALE, + /// Cleanup destructible mesh settings + VER_UE4_CLEAN_DESTRUCTIBLE_SETTINGS, + /// CharacterMovementComponent refactor of AdjustUpperHemisphereImpact and deprecation of some associated vars. + VER_UE4_CHARACTER_MOVEMENT_UPPER_IMPACT_BEHAVIOR, + /// Changed Blueprint math equality functions for vectors and rotators to operate as a "nearly" equals rather than "exact" + VER_UE4_BP_MATH_VECTOR_EQUALITY_USES_EPSILON, + /// Static lighting support was re-added to foliage, and mobility was returned to static + VER_UE4_FOLIAGE_STATIC_LIGHTING_SUPPORT, + /// Added composite fonts to Slate font info + VER_UE4_SLATE_COMPOSITE_FONTS, + /// Remove UDEPRECATED_SaveGameSummary, required for UWorld::Serialize + VER_UE4_REMOVE_SAVEGAMESUMMARY, + + /// Remove bodyseutp serialization from skeletal mesh component + VER_UE4_REMOVE_SKELETALMESH_COMPONENT_BODYSETUP_SERIALIZATION, + /// Made Slate font data use bulk data to store the embedded font data + VER_UE4_SLATE_BULK_FONT_DATA, + /// Add new friction behavior in ProjectileMovementComponent. + VER_UE4_ADD_PROJECTILE_FRICTION_BEHAVIOR, + /// Add axis settings enum to MovementComponent. + VER_UE4_MOVEMENTCOMPONENT_AXIS_SETTINGS, + /// Switch to new interactive comments, requires boundry conversion to preserve previous states + VER_UE4_GRAPH_INTERACTIVE_COMMENTBUBBLES, + /// Landscape serializes physical materials for collision objects + VER_UE4_LANDSCAPE_SERIALIZE_PHYSICS_MATERIALS, + /// Rename Visiblity on widgets to Visibility + VER_UE4_RENAME_WIDGET_VISIBILITY, + /// add track curves for animation + VER_UE4_ANIMATION_ADD_TRACKCURVES, + /// Removed BranchingPoints from AnimMontages and converted them to regular AnimNotifies. + VER_UE4_MONTAGE_BRANCHING_POINT_REMOVAL, + /// Enforce const-correctness in Blueprint implementations of native C++ const class methods + VER_UE4_BLUEPRINT_ENFORCE_CONST_IN_FUNCTION_OVERRIDES, + /// Added pivot to widget components, need to load old versions as a 0,0 pivot, new default is 0.5,0.5 + VER_UE4_ADD_PIVOT_TO_WIDGET_COMPONENT, + /// Added finer control over when AI Pawns are automatically possessed. Also renamed Pawn.AutoPossess to Pawn.AutoPossessPlayer indicate this was a setting for players and not AI. + VER_UE4_PAWN_AUTO_POSSESS_AI, + /// Added serialization of timezone to FTextHistory for AsDate operations. + VER_UE4_FTEXT_HISTORY_DATE_TIMEZONE, + /// Sort ActiveBoneIndices on lods so that we can avoid doing it at run time + VER_UE4_SORT_ACTIVE_BONE_INDICES, + /// Added per-frame material uniform expressions + VER_UE4_PERFRAME_MATERIAL_UNIFORM_EXPRESSIONS, + /// Make MikkTSpace the default tangent space calculation method for static meshes. + VER_UE4_MIKKTSPACE_IS_DEFAULT, + /// Only applies to cooked files, grass cooking support. + VER_UE4_LANDSCAPE_GRASS_COOKING, + /// Fixed code for using the bOrientMeshEmitters property. + VER_UE4_FIX_SKEL_VERT_ORIENT_MESH_PARTICLES, + /// Do not change landscape section offset on load under world composition + VER_UE4_LANDSCAPE_STATIC_SECTION_OFFSET, + /// New options for navigation data runtime generation (static, modifiers only, dynamic) + VER_UE4_ADD_MODIFIERS_RUNTIME_GENERATION, + /// Tidied up material's handling of masked blend mode. + VER_UE4_MATERIAL_MASKED_BLENDMODE_TIDY, + /// Original version of VER_UE4_MERGED_ADD_MODIFIERS_RUNTIME_GENERATION_TO_4_7; renumbered to prevent blocking promotion in main. + VER_UE4_MERGED_ADD_MODIFIERS_RUNTIME_GENERATION_TO_4_7_DEPRECATED, + /// Original version of VER_UE4_AFTER_MERGED_ADD_MODIFIERS_RUNTIME_GENERATION_TO_4_7; renumbered to prevent blocking promotion in main. + VER_UE4_AFTER_MERGED_ADD_MODIFIERS_RUNTIME_GENERATION_TO_4_7_DEPRECATED, + /// After merging VER_UE4_ADD_MODIFIERS_RUNTIME_GENERATION into 4.7 branch + VER_UE4_MERGED_ADD_MODIFIERS_RUNTIME_GENERATION_TO_4_7, + /// After merging VER_UE4_ADD_MODIFIERS_RUNTIME_GENERATION into 4.7 branch + VER_UE4_AFTER_MERGING_ADD_MODIFIERS_RUNTIME_GENERATION_TO_4_7, + /// Landscape grass weightmap data is now generated in the editor and serialized. + VER_UE4_SERIALIZE_LANDSCAPE_GRASS_DATA, + /// New property to optionally prevent gpu emitters clearing existing particles on Init(). + VER_UE4_OPTIONALLY_CLEAR_GPU_EMITTERS_ON_INIT, + /// Also store the Material guid with the landscape grass data + VER_UE4_SERIALIZE_LANDSCAPE_GRASS_DATA_MATERIAL_GUID, + /// Make sure that all template components from blueprint generated classes are flagged as public + VER_UE4_BLUEPRINT_GENERATED_CLASS_COMPONENT_TEMPLATES_PUBLIC, + /// Split out creation method on ActorComponents to distinguish between native, instance, and simple or user construction script + VER_UE4_ACTOR_COMPONENT_CREATION_METHOD, + /// K2Node_Event now uses FMemberReference for handling references + VER_UE4_K2NODE_EVENT_MEMBER_REFERENCE, + /// FPropertyTag stores GUID of struct + VER_UE4_STRUCT_GUID_IN_PROPERTY_TAG, + /// Remove unused UPolys from UModel cooked content + VER_UE4_REMOVE_UNUSED_UPOLYS_FROM_UMODEL, + /// This doesn't do anything except trigger a rebuild on HISMC cluster trees, in this case to get a good "occlusion query" level + VER_UE4_REBUILD_HIERARCHICAL_INSTANCE_TREES, + /// Package summary includes an CompatibleWithEngineVersion field, separately to the version it's saved with + VER_UE4_PACKAGE_SUMMARY_HAS_COMPATIBLE_ENGINE_VERSION, + /// Track UCS modified properties on Actor Components + VER_UE4_TRACK_UCS_MODIFIED_PROPERTIES, + /// Allowed landscape spline meshes to be stored into landscape streaming levels rather than the spline's level + VER_UE4_LANDSCAPE_SPLINE_CROSS_LEVEL_MESHES, + /// Deprecate the variables used for sizing in the designer on UUserWidget + VER_UE4_DEPRECATE_USER_WIDGET_DESIGN_SIZE, + /// Make the editor views array dynamically sized + VER_UE4_ADD_EDITOR_VIEWS, + /// Updated foliage to work with either FoliageType assets or blueprint classes + VER_UE4_FOLIAGE_WITH_ASSET_OR_CLASS, + /// Allows PhysicsSerializer to serialize shapes and actors for faster load times + VER_UE4_BODYINSTANCE_BINARY_SERIALIZATION, + /// Added fastcall data serialization directly in UFunction + VER_UE4_SERIALIZE_BLUEPRINT_EVENTGRAPH_FASTCALLS_IN_UFUNCTION, + /// Changes to USplineComponent and FInterpCurve + VER_UE4_INTERPCURVE_SUPPORTS_LOOPING, + /// Material Instances overriding base material LOD transitions + VER_UE4_MATERIAL_INSTANCE_BASE_PROPERTY_OVERRIDES_DITHERED_LOD_TRANSITION, + /// Serialize ES2 textures separately rather than overwriting the properties used on other platforms + VER_UE4_SERIALIZE_LANDSCAPE_ES2_TEXTURES, + /// Constraint motor velocity is broken into per-component + VER_UE4_CONSTRAINT_INSTANCE_MOTOR_FLAGS, + /// Serialize bIsConst in FEdGraphPinType + VER_UE4_SERIALIZE_PINTYPE_CONST, + /// Change UMaterialFunction::LibraryCategories to LibraryCategoriesText (old assets were saved before auto-conversion of FArrayProperty was possible) + VER_UE4_LIBRARY_CATEGORIES_AS_FTEXT, + /// Check for duplicate exports while saving packages. + VER_UE4_SKIP_DUPLICATE_EXPORTS_ON_SAVE_PACKAGE, + /// Pre-gathering of gatherable, localizable text in packages to optimize text gathering operation times + VER_UE4_SERIALIZE_TEXT_IN_PACKAGES, + /// Added pivot to widget components, need to load old versions as a 0,0 pivot, new default is 0.5,0.5 + VER_UE4_ADD_BLEND_MODE_TO_WIDGET_COMPONENT, + /// Added lightmass primitive setting + VER_UE4_NEW_LIGHTMASS_PRIMITIVE_SETTING, + /// Deprecate NoZSpring property on spring nodes to be replaced with TranslateZ property + VER_UE4_REPLACE_SPRING_NOZ_PROPERTY, + /// Keep enums tight and serialize their values as pairs of FName and value. Don't insert dummy values. + VER_UE4_TIGHTLY_PACKED_ENUMS, + /// Changed Asset import data to serialize file meta data as JSON + VER_UE4_ASSET_IMPORT_DATA_AS_JSON, + /// Legacy gamma support for textures. + VER_UE4_TEXTURE_LEGACY_GAMMA, + /// Added WithSerializer for basic native structures like FVector, FColor etc to improve serialization performance + VER_UE4_ADDED_NATIVE_SERIALIZATION_FOR_IMMUTABLE_STRUCTURES, + /// Deprecated attributes that override the style on UMG widgets + VER_UE4_DEPRECATE_UMG_STYLE_OVERRIDES, + /// Shadowmap penumbra size stored + VER_UE4_STATIC_SHADOWMAP_PENUMBRA_SIZE, + /// Fix BC on Niagara effects from the data object and dev UI changes. + VER_UE4_NIAGARA_DATA_OBJECT_DEV_UI_FIX, + /// Fixed the default orientation of widget component so it faces down +x + VER_UE4_FIXED_DEFAULT_ORIENTATION_OF_WIDGET_COMPONENT, + /// Removed bUsedWithUI flag from UMaterial and replaced it with a new material domain for UI + VER_UE4_REMOVED_MATERIAL_USED_WITH_UI_FLAG, + /// Added braking friction separate from turning friction. + VER_UE4_CHARACTER_MOVEMENT_ADD_BRAKING_FRICTION, + /// Removed TTransArrays from UModel + VER_UE4_BSP_UNDO_FIX, + /// Added default value to dynamic parameter. + VER_UE4_DYNAMIC_PARAMETER_DEFAULT_VALUE, + /// Added ExtendedBounds to StaticMesh + VER_UE4_STATIC_MESH_EXTENDED_BOUNDS, + /// Added non-linear blending to anim transitions, deprecating old types + VER_UE4_ADDED_NON_LINEAR_TRANSITION_BLENDS, + /// AO Material Mask texture + VER_UE4_AO_MATERIAL_MASK, + /// Replaced navigation agents selection with single structure + VER_UE4_NAVIGATION_AGENT_SELECTOR, + /// Mesh particle collisions consider particle size. + VER_UE4_MESH_PARTICLE_COLLISIONS_CONSIDER_PARTICLE_SIZE, + /// Adjacency buffer building no longer automatically handled based on triangle count, user-controlled + VER_UE4_BUILD_MESH_ADJ_BUFFER_FLAG_EXPOSED, + /// Change the default max angular velocity + VER_UE4_MAX_ANGULAR_VELOCITY_DEFAULT, + /// Build Adjacency index buffer for clothing tessellation + VER_UE4_APEX_CLOTH_TESSELLATION, + /// Added DecalSize member, solved backward compatibility + VER_UE4_DECAL_SIZE, + /// Keep only package names in StringAssetReferencesMap + VER_UE4_KEEP_ONLY_PACKAGE_NAMES_IN_STRING_ASSET_REFERENCES_MAP, + /// Support sound cue not saving out editor only data + VER_UE4_COOKED_ASSETS_IN_EDITOR_SUPPORT, + /// Updated dialogue wave localization gathering logic. + VER_UE4_DIALOGUE_WAVE_NAMESPACE_AND_CONTEXT_CHANGES, + /// Renamed MakeRot MakeRotator and rearranged parameters. + VER_UE4_MAKE_ROT_RENAME_AND_REORDER, + /// K2Node_Variable will properly have the VariableReference Guid set if available + VER_UE4_K2NODE_VAR_REFERENCEGUIDS, + /// Added support for sound concurrency settings structure and overrides + VER_UE4_SOUND_CONCURRENCY_PACKAGE, + /// Changing the default value for focusable user widgets to false + VER_UE4_USERWIDGET_DEFAULT_FOCUSABLE_FALSE, + /// Custom event nodes implicitly set 'const' on array and non-array pass-by-reference input params + VER_UE4_BLUEPRINT_CUSTOM_EVENT_CONST_INPUT, + /// Renamed HighFrequencyGain to LowPassFilterFrequency + VER_UE4_USE_LOW_PASS_FILTER_FREQ, + /// UAnimBlueprintGeneratedClass can be replaced by a dynamic class. Use TSubclassOf UAnimInstance instead. + VER_UE4_NO_ANIM_BP_CLASS_IN_GAMEPLAY_CODE, + /// The SCS keeps a list of all nodes in its hierarchy rather than recursively building it each time it is requested + VER_UE4_SCS_STORES_ALLNODES_ARRAY, + /// Moved StartRange and EndRange in UFbxAnimSequenceImportData to use FInt32Interval + VER_UE4_FBX_IMPORT_DATA_RANGE_ENCAPSULATION, + /// Adding a new root scene component to camera component + VER_UE4_CAMERA_COMPONENT_ATTACH_TO_ROOT, + /// Updating custom material expression nodes for instanced stereo implementation + VER_UE4_INSTANCED_STEREO_UNIFORM_UPDATE, + /// Texture streaming min and max distance to handle HLOD + VER_UE4_STREAMABLE_TEXTURE_MIN_MAX_DISTANCE, + /// Fixing up invalid struct-to-struct pin connections by injecting available conversion nodes + VER_UE4_INJECT_BLUEPRINT_STRUCT_PIN_CONVERSION_NODES, + /// Saving tag data for Array Property's inner property + VER_UE4_INNER_ARRAY_TAG_INFO, + /// Fixed duplicating slot node names in skeleton due to skeleton preload on compile + VER_UE4_FIX_SLOT_NAME_DUPLICATION, + /// Texture streaming using AABBs instead of Spheres + VER_UE4_STREAMABLE_TEXTURE_AABB, + /// FPropertyTag stores GUID of property + VER_UE4_PROPERTY_GUID_IN_PROPERTY_TAG, + /// Name table hashes are calculated and saved out rather than at load time + VER_UE4_NAME_HASHES_SERIALIZED, + /// Updating custom material expression nodes for instanced stereo implementation refactor + VER_UE4_INSTANCED_STEREO_UNIFORM_REFACTOR, + /// Added compression to the shader resource for memory savings + VER_UE4_COMPRESSED_SHADER_RESOURCES, + /// Cooked files contain the dependency graph for the event driven loader (the serialization is largely independent of the use of the new loader) + VER_UE4_PRELOAD_DEPENDENCIES_IN_COOKED_EXPORTS, + /// Cooked files contain the TemplateIndex used by the event driven loader (the serialization is largely independent of the use of the new loader, i.e. this will be null if cooking for the old loader) + VER_UE4_TemplateIndex_IN_COOKED_EXPORTS, + /// FPropertyTag includes contained type(s) for Set and Map properties + VER_UE4_PROPERTY_TAG_SET_MAP_SUPPORT, + /// Added SearchableNames to the package summary and asset registry + VER_UE4_ADDED_SEARCHABLE_NAMES, + /// Increased size of SerialSize and SerialOffset in export map entries to 64 bit, allow support for bigger files + VER_UE4_64BIT_EXPORTMAP_SERIALSIZES, + /// Sky light stores IrradianceMap for mobile renderer. + VER_UE4_SKYLIGHT_MOBILE_IRRADIANCE_MAP, + /// Added flag to control sweep behavior while walking in UCharacterMovementComponent. + VER_UE4_ADDED_SWEEP_WHILE_WALKING_FLAG, + /// StringAssetReference changed to SoftObjectPath and swapped to serialize as a name+string instead of a string + VER_UE4_ADDED_SOFT_OBJECT_PATH, + /// Changed the source orientation of point lights to match spot lights (z axis) + VER_UE4_POINTLIGHT_SOURCE_ORIENTATION, + /// LocalizationId has been added to the package summary (editor-only) + VER_UE4_ADDED_PACKAGE_SUMMARY_LOCALIZATION_ID, + /// Fixed case insensitive hashes of wide strings containing character values from 128-255 + VER_UE4_FIX_WIDE_STRING_CRC, + /// 4.22 filler + VER_UE4_FILLER_22, + /// Added package owner to allow private references + VER_UE4_ADDED_PACKAGE_OWNER, + /// Changed the data layout for skin weight profile data + VER_UE4_SKINWEIGHT_PROFILE_DATA_LAYOUT_CHANGES, + /// Added import that can have package different than their outer + VER_UE4_NON_OUTER_PACKAGE_IMPORT, + /// Added DependencyFlags to AssetRegistry + VER_UE4_ASSETREGISTRY_DEPENDENCYFLAGS, + /// Fixed corrupt licensee flag in 4.26 assets + VER_UE4_CORRECT_LICENSEE_FLAG, + + VER_UE4_AUTOMATIC_VERSION_PLUS_ONE, + /// The newest specified version of the Unreal Engine. + VER_UE4_AUTOMATIC_VERSION = VER_UE4_AUTOMATIC_VERSION_PLUS_ONE - 1, + + /// 4.0 + VER_UE4_0 = 342, + /// 4.1 + VER_UE4_1 = 352, + /// 4.2 + VER_UE4_2 = 363, + /// 4.3 + VER_UE4_3 = 382, + /// 4.4 + VER_UE4_4 = 385, + /// 4.5 + VER_UE4_5 = 401, + /// 4.6 + VER_UE4_6 = 413, + /// 4.7 + VER_UE4_7 = 434, + /// 4.8 + VER_UE4_8 = 451, + /// 4.9 + VER_UE4_9 = 482, + /// 4.10 + VER_UE4_10 = 482, + /// 4.11 + VER_UE4_11 = 498, + /// 4.12 + VER_UE4_12 = 504, + /// 4.13 + VER_UE4_13 = 505, + /// 4.14 + VER_UE4_14 = 508, + /// 4.15 + VER_UE4_15 = 510, + /// 4.16 + VER_UE4_16 = 513, + /// 4.17 + VER_UE4_17 = 513, + /// 4.18 + VER_UE4_18 = 514, + /// 4.19 + VER_UE4_19 = 516, + /// 4.20 + VER_UE4_20 = 516, + /// 4.21 + VER_UE4_21 = 517, + /// 4.22 + VER_UE4_22 = 517, + /// 4.23 + VER_UE4_23 = 517 + 1, // actually 517; set to 518 to ensure 4.22 doesn't have FEditorObjectVersion::CultureInvariantTextSerializationKeyStability + /// 4.24 + VER_UE4_24 = 518 + 1, + /// 4.25 + VER_UE4_25 = 518 + 1, + /// 4.26 + VER_UE4_26 = 519 + 1, + /// 4.27 + VER_UE4_27 = 522 + 1, + }; +} diff --git a/Translation/UAssetAPI/Unversioned/FFragment.cs b/Translation/UAssetAPI/Unversioned/FFragment.cs new file mode 100644 index 0000000..d259efe --- /dev/null +++ b/Translation/UAssetAPI/Unversioned/FFragment.cs @@ -0,0 +1,54 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.Unversioned +{ + /// + /// Unversioned header fragment. + /// + public class FFragment + { + /// + /// Number of properties to skip before values. + /// + public byte SkipNum; + + public bool bHasAnyZeroes = false; + + /// + /// Number of subsequent property values stored. + /// + public byte ValueNum = 0; + + /// + /// Is this the last fragment of the header? + /// + public bool bIsLast = false; + + private static readonly uint SkipMax = 127; + private static readonly uint ValueMax = 127; + private static readonly uint SkipNumMask = 0x007fu; + private static readonly uint HasZeroMask = 0x0080u; + private static readonly int ValueNumShift = 9; + private static readonly uint IsLastMask = 0x0100u; + + public ushort Pack() + { + return (ushort)(SkipNum | (bHasAnyZeroes ? HasZeroMask : 0) | (ushort)(ValueNum << ValueNumShift) | (bIsLast ? IsLastMask : 0)); + } + + public static FFragment Unpack(ushort Int) + { + FFragment Fragment = new FFragment(); + Fragment.SkipNum = (byte)(Int & SkipNumMask); + Fragment.bHasAnyZeroes = (Int & HasZeroMask) != 0; + Fragment.ValueNum = (byte)(Int >> ValueNumShift); + Fragment.bIsLast = (Int & IsLastMask) != 0; + return Fragment; + } + } +} diff --git a/Translation/UAssetAPI/Unversioned/FUnversionedHeader.cs b/Translation/UAssetAPI/Unversioned/FUnversionedHeader.cs new file mode 100644 index 0000000..a66326c --- /dev/null +++ b/Translation/UAssetAPI/Unversioned/FUnversionedHeader.cs @@ -0,0 +1,105 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UAssetAPI.UnrealTypes; + +namespace UAssetAPI.Unversioned +{ + // https://github.com/EpicGames/UnrealEngine/blob/master/Engine/Source/Runtime/CoreUObject/Private/Serialization/UnversionedPropertySerialization.cpp#L414 + + /// + /// List of serialized property indices and which of them are non-zero. + /// Serialized as a stream of 16-bit skip-x keep-y fragments and a zero bitmask. + /// + public class FUnversionedHeader + { + public List Fragments; + public byte[] ZeroMask; + public bool bHasNonZeroValues = false; + + public void Read(AssetBinaryReader reader) + { + Fragments = new List(32); + + FFragment Fragment; + uint ZeroMaskNum = 0; + uint UnmaskedNum = 0; + do + { + Fragment = FFragment.Unpack(reader.ReadUInt16()); + Fragments.Add(Fragment); + + if (Fragment.bHasAnyZeroes) + { + ZeroMaskNum += Fragment.ValueNum; + } + else + { + UnmaskedNum += Fragment.ValueNum; + } + } + while (!Fragment.bIsLast); + + if (ZeroMaskNum > 0) + { + LoadZeroMaskData(reader, ZeroMaskNum); + bHasNonZeroValues = UnmaskedNum > 0 || !CheckIfZeroMaskIsAllOnes(); + } + else + { + bHasNonZeroValues = UnmaskedNum > 0; + } + } + + public void LoadZeroMaskData(AssetBinaryReader reader, uint NumBits) + { + if (NumBits <= 8) + { + ZeroMask = reader.ReadBytes(1); + } + else if (NumBits <= 16) + { + ZeroMask = reader.ReadBytes(2); + } + else + { + int numWords = (int)(NumBits / 32) + 1; + ZeroMask = reader.ReadBytes(numWords * 4); + } + } + + public bool CheckIfZeroMaskIsAllOnes() + { + foreach (byte x in ZeroMask) + { + if (x != 0xFF) return false; + } + return true; + } + + public void Write(AssetBinaryWriter writer) + { + foreach (FFragment Fragment in Fragments) + { + writer.Write(Fragment.Pack()); + } + + if (ZeroMask.Length > 0) + { + writer.Write(ZeroMask); + } + } + + public bool HasValues() + { + return bHasNonZeroValues | (ZeroMask.Length > 0); + } + + public bool HasNonZeroValues() + { + return bHasNonZeroValues; + } + } +} diff --git a/Translation/UAssetAPI/git_commit.txt b/Translation/UAssetAPI/git_commit.txt new file mode 100644 index 0000000..9f6b835 --- /dev/null +++ b/Translation/UAssetAPI/git_commit.txt @@ -0,0 +1 @@ +73b79b0 diff --git a/Translation/WTT.sln b/Translation/WTT.sln new file mode 100644 index 0000000..baa25f7 --- /dev/null +++ b/Translation/WTT.sln @@ -0,0 +1,41 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.2.32602.215 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UAssetAPI", "UAssetAPI\UAssetAPI.csproj", "{178417EC-1177-413E-BE85-C83AECD64279}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WTT", "WTT\WTT.csproj", "{61F0054E-5D5C-48CC-AA70-A746DFAF4CED}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 + Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {178417EC-1177-413E-BE85-C83AECD64279}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {178417EC-1177-413E-BE85-C83AECD64279}.Debug|Any CPU.Build.0 = Debug|Any CPU + {178417EC-1177-413E-BE85-C83AECD64279}.Debug|x64.ActiveCfg = Debug|Any CPU + {178417EC-1177-413E-BE85-C83AECD64279}.Debug|x64.Build.0 = Debug|Any CPU + {178417EC-1177-413E-BE85-C83AECD64279}.Release|Any CPU.ActiveCfg = Release|Any CPU + {178417EC-1177-413E-BE85-C83AECD64279}.Release|Any CPU.Build.0 = Release|Any CPU + {178417EC-1177-413E-BE85-C83AECD64279}.Release|x64.ActiveCfg = Release|Any CPU + {178417EC-1177-413E-BE85-C83AECD64279}.Release|x64.Build.0 = Release|Any CPU + {61F0054E-5D5C-48CC-AA70-A746DFAF4CED}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {61F0054E-5D5C-48CC-AA70-A746DFAF4CED}.Debug|Any CPU.Build.0 = Debug|Any CPU + {61F0054E-5D5C-48CC-AA70-A746DFAF4CED}.Debug|x64.ActiveCfg = Debug|Any CPU + {61F0054E-5D5C-48CC-AA70-A746DFAF4CED}.Debug|x64.Build.0 = Debug|Any CPU + {61F0054E-5D5C-48CC-AA70-A746DFAF4CED}.Release|Any CPU.ActiveCfg = Release|Any CPU + {61F0054E-5D5C-48CC-AA70-A746DFAF4CED}.Release|Any CPU.Build.0 = Release|Any CPU + {61F0054E-5D5C-48CC-AA70-A746DFAF4CED}.Release|x64.ActiveCfg = Release|Any CPU + {61F0054E-5D5C-48CC-AA70-A746DFAF4CED}.Release|x64.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {7A4553E8-6A4B-46A5-B429-7F9128492CAD} + EndGlobalSection +EndGlobal diff --git a/Translation/WTT/Exceptions/DuplicateKeyException.cs b/Translation/WTT/Exceptions/DuplicateKeyException.cs new file mode 100644 index 0000000..991564f --- /dev/null +++ b/Translation/WTT/Exceptions/DuplicateKeyException.cs @@ -0,0 +1,18 @@ +namespace WhackTranslationTool.Exceptions; + +public class DuplicateKeyException : Exception +{ + public DuplicateKeyException() + { + } + + public DuplicateKeyException(string message) + : base(message) + { + } + + public DuplicateKeyException(string message, Exception inner) + : base(message, inner) + { + } +} diff --git a/Translation/WTT/Exceptions/MissingKeyException.cs b/Translation/WTT/Exceptions/MissingKeyException.cs new file mode 100644 index 0000000..7bcddfb --- /dev/null +++ b/Translation/WTT/Exceptions/MissingKeyException.cs @@ -0,0 +1,18 @@ +namespace WhackTranslationTool.Exceptions; + +public class MissingKeyException : Exception +{ + public MissingKeyException() + { + } + + public MissingKeyException(string message) + : base(message) + { + } + + public MissingKeyException(string message, Exception inner) + : base(message, inner) + { + } +} diff --git a/Translation/WTT/Exceptions/UnsupportedAssetException.cs b/Translation/WTT/Exceptions/UnsupportedAssetException.cs new file mode 100644 index 0000000..78beba5 --- /dev/null +++ b/Translation/WTT/Exceptions/UnsupportedAssetException.cs @@ -0,0 +1,18 @@ +namespace WhackTranslationTool.Exceptions; + +public class UnsupportedAssetException : Exception +{ + public UnsupportedAssetException() + { + } + + public UnsupportedAssetException(string message) + : base(message) + { + } + + public UnsupportedAssetException(string message, Exception inner) + : base(message, inner) + { + } +} \ No newline at end of file diff --git a/Translation/WTT/ExportSettings.cs b/Translation/WTT/ExportSettings.cs new file mode 100644 index 0000000..2df5768 --- /dev/null +++ b/Translation/WTT/ExportSettings.cs @@ -0,0 +1,10 @@ +namespace WhackTranslationTool; + +public class ExportSettings +{ + /// + /// Export Korean message along with the Japanese message. + /// Useful for cross-referencing meaning of a phrase or word. + /// + public bool ExportKoreanMessage { get; set; } = true; +} \ No newline at end of file diff --git a/Translation/WTT/Program.cs b/Translation/WTT/Program.cs new file mode 100644 index 0000000..abdb932 --- /dev/null +++ b/Translation/WTT/Program.cs @@ -0,0 +1,139 @@ +using WhackTranslationTool; + +string? basePath = null; // @"WindowsNoEditor\Mercury\Content\Message"; + +static string ResolveFileOverwrite(string path) +{ + while (true) + { + Console.WriteLine($"A file already exists at '{path}'"); + Console.Write("Overwrite (y/n)? "); + + var input = Console.ReadLine()!.Trim().ToLowerInvariant(); + + if (input == "y") + { + return path; + } + + if (input == "n") + { + Console.Write("Enter a new path: '"); + return Console.ReadLine()!.Trim(); + } + + Console.WriteLine($"Invalid selection!" + Environment.NewLine); + } +} + +static string GetAssetFilename(string path) +{ + return Path.GetFileNameWithoutExtension(path) + ".uasset"; +} + +while (true) +{ + Console.WriteLine("[whack Translation Tool]"); + while (basePath == null || !Directory.Exists(basePath)) + { + if (basePath != null) + Console.WriteLine("Invalid path to Message directory."); + Console.Write("Path to Message directory: "); + basePath = Console.ReadLine()!.Trim(); + continue; + } + Console.WriteLine("'e' for export, 'i' for import, 'bulk_import', 'bulk_export', 'q' to quit"); + Console.WriteLine("reminder: don't screw up"); + Console.Write("Action: "); + var action = Console.ReadLine()!.Trim().ToLowerInvariant(); + switch (action) + { + case "bulk_export": + { + var files = Directory.GetFiles(basePath, "*.uasset"); + foreach (var tableName in files) + { + var exporter = new TableExporter(Path.Combine(basePath, tableName)); + + var targetPath = Path.GetFileName(Path.ChangeExtension(tableName, "toml")); + if (File.Exists(targetPath)) + { + targetPath = ResolveFileOverwrite(targetPath); + } + + Console.WriteLine($"Exporting to {targetPath}"); + using StreamWriter writer = File.CreateText(targetPath); + exporter.WriteTo(writer); + writer.Flush(); + } + + break; + } + case "bulk_import": + { + Console.WriteLine(Environment.NewLine + "[Bulk Import Mode]"); + Console.Write("Enter the path to the directory of TOML files: "); + var tomlFolder = Console.ReadLine()!; + Console.Write("Enter the path to the uasset directory: "); + var assetFolder = Console.ReadLine()!; + Console.Write("Enter the path to the output uasset directory: "); + var outputFolder = Console.ReadLine()!; + var files = Directory.GetFiles(tomlFolder, "*.toml"); + foreach (var tableName in files) + { + var assetFilename = GetAssetFilename(tableName); + var importer = new TableImporter(tableName, Path.Combine(assetFolder, assetFilename)); + var outputPath = Path.Combine(outputFolder, assetFilename); + Console.WriteLine($"Exporting to {outputPath}"); + importer.Write(outputPath); + } + break; + } + case "e": + { + Console.WriteLine(Environment.NewLine + "[Export Mode]"); + Console.Write("Enter the name of the asset (e.g., 'WelcomeMessage.uasset'): "); + var tableName = Console.ReadLine()!.Trim(); + var exporter = new TableExporter(Path.Combine(basePath, tableName)); + + var targetPath = Path.ChangeExtension(tableName, "toml"); + if (File.Exists(targetPath)) + { + targetPath = ResolveFileOverwrite(targetPath); + } + + using StreamWriter writer = File.CreateText(targetPath); + exporter.WriteTo(writer); + writer.Flush(); + break; + } + + case "i": + { + Console.WriteLine(Environment.NewLine + "[Import Mode]"); + Console.Write("Enter the path to the toml file (e.g., 'WelcomeMessage.toml'): "); + var importPath = Console.ReadLine()!.Trim(); + Console.Write("Enter the path to the asset (or press enter for default): "); + var assetPath = Console.ReadLine()!.Trim(); + if (assetPath.Length < 1) + assetPath = Path.Combine(basePath, GetAssetFilename(importPath)); + var importer = new TableImporter(importPath, assetPath); + Console.Write("Enter the output path or folder: "); + var output = Console.ReadLine()!.Trim(); + if (Directory.Exists(output)) + output = Path.Combine(output, GetAssetFilename(importPath)); + if (File.Exists(output)) + output = ResolveFileOverwrite(output); + importer.Write(output); + break; + } + + case "q": + return; + + default: + Console.WriteLine("Unrecognized option."); + break; + } + Console.WriteLine(); +} \ No newline at end of file diff --git a/Translation/WTT/TableConstants.cs b/Translation/WTT/TableConstants.cs new file mode 100644 index 0000000..6faee7f --- /dev/null +++ b/Translation/WTT/TableConstants.cs @@ -0,0 +1,10 @@ +using UAssetAPI.UnrealTypes; + +namespace WhackTranslationTool; + +public class TableConstants +{ + public const UE4Version UnrealVersion = UE4Version.VER_UE4_19; + // public const int JAPANESE_MESSAGE_INDEX = 0; + // public const int KOREAN_MESSAGE_INDEX = 6; +} \ No newline at end of file diff --git a/Translation/WTT/TableExporter.cs b/Translation/WTT/TableExporter.cs new file mode 100644 index 0000000..0ab423b --- /dev/null +++ b/Translation/WTT/TableExporter.cs @@ -0,0 +1,105 @@ +using Tommy; +using UAssetAPI; +using UAssetAPI.PropertyTypes.Structs; +using UAssetAPI.UnrealTypes; +using WhackTranslationTool.Exceptions; + +namespace WhackTranslationTool; + +public class TableExporter +{ + private readonly char[] _multilineChars = { '\n', '"' }; + private readonly ExportSettings _settings; + private Dictionary strings = new(); + + public TableExporter(string filename) : this(filename, new ExportSettings()) { } + + /// + /// Initializes a table exporter object + /// + /// Name of the uasset source file to export to toml + /// Export settings + /// When UAssetAPI fails to reconstruct the asset file + public TableExporter(string filename, ExportSettings settings) + { + _settings = settings; + + var asset = new UAsset(filename, TableConstants.UnrealVersion); + if (!asset.VerifyBinaryEquality()) + throw new UnsupportedAssetException($"'{asset.FilePath}' is not supported (no binary equality)"); + Read(asset); + } + + private TomlTable MessageDataToTomlTable(StructPropertyData entry) + { + var tomlTable = new TomlTable(); + + var japaneseValue = (entry.Value[0].RawValue as FString)?.Value; + if (japaneseValue != null) + tomlTable.Add("JapaneseMessage", new TomlString + { + IsMultiline = japaneseValue.IndexOfAny(_multilineChars) != -1, + Value = japaneseValue + }); + + var koreanValue = (entry.Value[6].RawValue as FString)?.Value; + if (koreanValue != null) + tomlTable.Add("KoreanMessage", new TomlString + { + IsMultiline = koreanValue.IndexOfAny(_multilineChars) != -1, + Value = koreanValue + }); + + return tomlTable; + } + + private TomlTable CharacterMessageDataToTomlTable(StructPropertyData entry) + { + var tomlTable = new TomlTable(); + + var japaneseValue = (entry.Value[3].RawValue as FString)?.Value; + if (japaneseValue != null) + tomlTable.Add("JapaneseMessage", new TomlString + { + IsMultiline = japaneseValue.IndexOfAny(_multilineChars) != -1, + Value = japaneseValue + }); + + var koreanValue = (entry.Value[9].RawValue as FString)?.Value; + if (koreanValue != null) + tomlTable.Add("KoreanMessage", new TomlString + { + IsMultiline = koreanValue.IndexOfAny(_multilineChars) != -1, + Value = koreanValue + }); + + return tomlTable; + } + + private void Read(UAsset asset) + { + var export = asset.Exports[0] as DataTableExport; + var table = export?.Table.Data!; + + foreach (var entry in table) + { + var name = entry.Name.ToString(); + if (strings.ContainsKey(name)) + throw new DuplicateKeyException($"duplicate key '{name}' found for file {asset.FilePath}"); + strings.Add(name, entry.StructType.Value.Value switch + { + "MessageData" => MessageDataToTomlTable(entry), + "CharaMessageData" => CharacterMessageDataToTomlTable(entry), + _ => throw new Exception($"Unhandled type '{entry.StructType}'") + }); + } + } + + public void WriteTo(TextWriter writer) + { + var toml = new TomlTable(); + foreach (var str in strings) + toml.Add(str.Key, str.Value); + toml.WriteTo(writer); + } +} \ No newline at end of file diff --git a/Translation/WTT/TableImporter.cs b/Translation/WTT/TableImporter.cs new file mode 100644 index 0000000..057c13d --- /dev/null +++ b/Translation/WTT/TableImporter.cs @@ -0,0 +1,77 @@ +using System.Text; +using Tommy; +using UAssetAPI; +using UAssetAPI.PropertyTypes.Structs; +using UAssetAPI.UnrealTypes; +using WhackTranslationTool.Exceptions; + +namespace WhackTranslationTool; + +public class TableImporter +{ + private Dictionary strings = new(); + private UAsset asset; + + /// + /// + /// + /// Path to the toml source import file + /// Path to the target uasset file + /// When UAssetAPI fails to reconstruct the asset file + public TableImporter(string tomlPath, string assetPath) + { + asset = new UAsset(assetPath, TableConstants.UnrealVersion); + if (!asset.VerifyBinaryEquality()) + { + throw new UnsupportedAssetException($"'{asset.FilePath}' is not supported (no binary equality)"); + } + + ReadStrings(tomlPath); + UpdateAssetStrings(); + } + + private void ReadStrings(string tomlPath) + { + using var reader = File.OpenText(tomlPath); + var table = TOML.Parse(reader); + foreach (var (key, value) in table.RawTable) + { + if (string.IsNullOrEmpty(key)) + throw new InvalidDataException($"key '{key}' is invalid"); + if (strings.ContainsKey(key)) + throw new DuplicateKeyException($"duplicate key '{key}' found for file {tomlPath} ({asset.FilePath})"); + strings.Add(key, value.HasKey("JapaneseMessage") ? value["JapaneseMessage"].AsString.Value : null); + } + } + + private void UpdateAssetStrings() + { + var export = asset.Exports[0] as DataTableExport; + var table = export?.Table.Data!; + + foreach (var entry in table) + { + var name = entry.Name.ToString(); + if (!strings.ContainsKey(name)) + { + // throw new MissingKeyException($"missing key '{name}' in toml file for {asset.FilePath}"); + Console.WriteLine($"Warning: skipping missing key '{name}' in toml file for {asset.FilePath}"); + continue; + } + + // index of JapaneseMessage + var index = entry.StructType.Value.Value switch + { + "MessageData" => 0, + "CharaMessageData" => 3, + _ => throw new Exception($"Unhandled type '{entry.StructType}'") + }; + entry.Value[index].SetObject(FString.FromString(strings[name])); + } + } + + public void Write(string newAssetPath) + { + asset.Write(newAssetPath); + } +} \ No newline at end of file diff --git a/Translation/WTT/WTT.csproj b/Translation/WTT/WTT.csproj new file mode 100644 index 0000000..af0b0e3 --- /dev/null +++ b/Translation/WTT/WTT.csproj @@ -0,0 +1,18 @@ + + + + Exe + net6.0 + enable + enable + + + + + + + + + + + diff --git a/galliumhook/.gitignore b/galliumhook/.gitignore new file mode 100644 index 0000000..8dd4607 --- /dev/null +++ b/galliumhook/.gitignore @@ -0,0 +1,398 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore + +# User-specific files +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Mono auto generated files +mono_crash.* + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Ww][Ii][Nn]32/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ +[Ll]ogs/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUnit +*.VisualState.xml +TestResult.xml +nunit-*.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# ASP.NET Scaffolding +ScaffoldingReadMe.txt + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.log +*.tlog +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Coverlet is a free, cross platform Code Coverage Tool +coverage*.json +coverage*.xml +coverage*.info + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# NuGet Symbol Packages +*.snupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx +*.appxbundle +*.appxupload + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!?*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser +*- [Bb]ackup.rdl +*- [Bb]ackup ([0-9]).rdl +*- [Bb]ackup ([0-9][0-9]).rdl + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio 6 auto-generated project file (contains which files were open etc.) +*.vbp + +# Visual Studio 6 workspace and project file (working project files containing files to include in project) +*.dsw +*.dsp + +# Visual Studio 6 technical files +*.ncb +*.aps + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# CodeRush personal settings +.cr/personal + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ + +# Visual Studio History (VSHistory) files +.vshistory/ + +# BeatPulse healthcheck temp database +healthchecksdb + +# Backup folder for Package Reference Convert tool in Visual Studio 2017 +MigrationBackup/ + +# Ionide (cross platform F# VS Code tools) working folder +.ionide/ + +# Fody - auto-generated XML schema +FodyWeavers.xsd + +# VS Code files for those working on multiple tools +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +*.code-workspace + +# Local History for Visual Studio Code +.history/ + +# Windows Installer files from build outputs +*.cab +*.msi +*.msix +*.msm +*.msp + +# JetBrains Rider +*.sln.iml \ No newline at end of file diff --git a/galliumhook/galliumhook.sln b/galliumhook/galliumhook.sln new file mode 100644 index 0000000..923ae05 --- /dev/null +++ b/galliumhook/galliumhook.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.2.32602.215 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "galliumhook", "galliumhook\galliumhook.vcxproj", "{34E927A3-13A1-4869-B262-C7AC8222C5ED}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libMinHook", "minhook-multihook\build\VC16\libMinHook.vcxproj", "{F142A341-5EE0-442D-A15F-98AE9B48DBAE}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {34E927A3-13A1-4869-B262-C7AC8222C5ED}.Debug|x64.ActiveCfg = Debug|x64 + {34E927A3-13A1-4869-B262-C7AC8222C5ED}.Debug|x64.Build.0 = Debug|x64 + {34E927A3-13A1-4869-B262-C7AC8222C5ED}.Release|x64.ActiveCfg = Release|x64 + {34E927A3-13A1-4869-B262-C7AC8222C5ED}.Release|x64.Build.0 = Release|x64 + {F142A341-5EE0-442D-A15F-98AE9B48DBAE}.Debug|x64.ActiveCfg = Debug|x64 + {F142A341-5EE0-442D-A15F-98AE9B48DBAE}.Debug|x64.Build.0 = Debug|x64 + {F142A341-5EE0-442D-A15F-98AE9B48DBAE}.Release|x64.ActiveCfg = Release|x64 + {F142A341-5EE0-442D-A15F-98AE9B48DBAE}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {BCD16084-010A-4B9A-B9F8-FE7666558CBD} + EndGlobalSection +EndGlobal diff --git a/galliumhook/galliumhook/dllmain.cpp b/galliumhook/galliumhook/dllmain.cpp new file mode 100644 index 0000000..f4b77b9 --- /dev/null +++ b/galliumhook/galliumhook/dllmain.cpp @@ -0,0 +1,99 @@ +// dllmain.cpp : Defines the entry point for the DLL application. +#include "pch.h" +#include +#include +#include +#include "MinHook.h" + +const int TARGET_WIDTH = 1080; +const int TARGET_HEIGHT = 1920; + +typedef int64_t(__fastcall* tWndProc)(HWND, UINT, WPARAM, WPARAM); +tWndProc WndProc; +tWndProc fpWndProc; + +typedef HWND(__stdcall* tCreateWindowExW)(DWORD dwExStyle, LPCWSTR lpClassName, LPCWSTR lpWindowName, DWORD dwStyle, int X, int Y, int nWidth, int nHeight, HWND hWndParent, HMENU hMenu, HINSTANCE hInstance, LPVOID lpParam); +tCreateWindowExW fpCreateWindowExW; +HWND __stdcall DetourCreateWindowExW(DWORD dwExStyle, LPCWSTR lpClassName, LPCWSTR lpWindowName, DWORD dwStyle, int X, int Y, int nWidth, int nHeight, HWND hWndParent, HMENU hMenu, HINSTANCE hInstance, LPVOID lpParam) +{ + nWidth = TARGET_WIDTH; + nHeight = TARGET_HEIGHT; + return fpCreateWindowExW(dwExStyle, lpClassName, lpWindowName, dwStyle, X, Y, nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam); +} + +int64_t __fastcall DetourWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, WPARAM lParam) +{ + if (uMsg == WM_GETMINMAXINFO) + { + DefWindowProc(hWnd, uMsg, wParam, lParam); + MINMAXINFO* pmmi = (MINMAXINFO*)lParam; + pmmi->ptMaxTrackSize.x = TARGET_WIDTH; + pmmi->ptMaxTrackSize.y = TARGET_HEIGHT; + + // is this needed? don't care because it works + SetWindowPos(hWnd, HWND_TOP, 0, 0, TARGET_WIDTH, TARGET_HEIGHT, SWP_NOMOVE | SWP_FRAMECHANGED); + return 0; + } + return fpWndProc(hWnd, uMsg, wParam, lParam); +} + +int CreateHooks() +{ + OutputDebugStringW(L"[galliumhook] CreateHooks()\r\n"); + auto base = (uint64_t)GetModuleHandleW(NULL); + WndProc = (tWndProc)(base + 0x72AE80ull); + + if (MH_Initialize() != MH_OK) + { + MessageBox(NULL, L"Couldn't initialize MinHook", L"galliumhook", MB_OK); + return 0; + } + + auto createResult = MH_CreateHook(WndProc, &DetourWndProc, reinterpret_cast(&fpWndProc)); + if (createResult != MH_OK) + { + MessageBox(NULL, L"Couldn't create WndProc hook", L"galliumhook", MB_OK); + return 0; + } + + if (MH_EnableHook(WndProc) != MH_OK) + { + MessageBox(NULL, L"Couldn't enable WndProc hook", L"galliumhook", MB_OK); + return 0; + } + + if (MH_CreateHook(&CreateWindowExW, &DetourCreateWindowExW, reinterpret_cast(&fpCreateWindowExW)) != MH_OK) + { + MessageBox(NULL, L"Couldn't create CreateWindowExW hook", L"galliumhook", MB_OK); + return 0; + } + + if (MH_EnableHook(&CreateWindowExW) != MH_OK) + { + MessageBox(NULL, L"Couldn't enable CreateWindowExW hook", L"galliumhook", MB_OK); + return 0; + } + + OutputDebugStringW(L"[galliumhook] CreateHooks() completed"); + return 0; +} + +BOOL APIENTRY DllMain( HMODULE hModule, + DWORD ul_reason_for_call, + LPVOID lpReserved + ) +{ + switch (ul_reason_for_call) + { + case DLL_PROCESS_ATTACH: + LoadLibrary(L"mercuryhook.dll"); + CreateHooks(); + break; + case DLL_THREAD_ATTACH: + case DLL_THREAD_DETACH: + case DLL_PROCESS_DETACH: + break; + } + return TRUE; +} + diff --git a/galliumhook/galliumhook/framework.h b/galliumhook/galliumhook/framework.h new file mode 100644 index 0000000..54b83e9 --- /dev/null +++ b/galliumhook/galliumhook/framework.h @@ -0,0 +1,5 @@ +#pragma once + +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +// Windows Header Files +#include diff --git a/galliumhook/galliumhook/galliumhook.vcxproj b/galliumhook/galliumhook/galliumhook.vcxproj new file mode 100644 index 0000000..97804f4 --- /dev/null +++ b/galliumhook/galliumhook/galliumhook.vcxproj @@ -0,0 +1,164 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 16.0 + Win32Proj + {34e927a3-13a1-4869-b262-c7ac8222c5ed} + galliumhook + 10.0 + + + + DynamicLibrary + true + v143 + Unicode + + + DynamicLibrary + false + v143 + true + Unicode + + + DynamicLibrary + true + v143 + Unicode + + + DynamicLibrary + false + v143 + true + Unicode + + + + + + + + + + + + + + + + + + + + + + Level3 + true + WIN32;_DEBUG;GALLIUMHOOK_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + Use + pch.h + + + Windows + true + false + + + + + Level3 + true + true + true + WIN32;NDEBUG;GALLIUMHOOK_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + Use + pch.h + + + Windows + true + true + true + false + + + + + Level3 + true + _DEBUG;GALLIUMHOOK_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + Use + pch.h + $(SolutionDir)minhook-multihook\include + + + Windows + true + false + + + + + Level3 + true + true + true + NDEBUG;GALLIUMHOOK_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + Use + pch.h + $(SolutionDir)minhook-multihook\include + + + Windows + true + true + true + false + + + + + + + + + + Create + Create + Create + Create + + + + + {f142a341-5ee0-442d-a15f-98ae9b48dbae} + + + + + + \ No newline at end of file diff --git a/galliumhook/galliumhook/galliumhook.vcxproj.filters b/galliumhook/galliumhook/galliumhook.vcxproj.filters new file mode 100644 index 0000000..1e57c7b --- /dev/null +++ b/galliumhook/galliumhook/galliumhook.vcxproj.filters @@ -0,0 +1,33 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + \ No newline at end of file diff --git a/galliumhook/galliumhook/pch.cpp b/galliumhook/galliumhook/pch.cpp new file mode 100644 index 0000000..64b7eef --- /dev/null +++ b/galliumhook/galliumhook/pch.cpp @@ -0,0 +1,5 @@ +// pch.cpp: source file corresponding to the pre-compiled header + +#include "pch.h" + +// When you are using pre-compiled headers, this source file is necessary for compilation to succeed. diff --git a/galliumhook/galliumhook/pch.h b/galliumhook/galliumhook/pch.h new file mode 100644 index 0000000..885d5d6 --- /dev/null +++ b/galliumhook/galliumhook/pch.h @@ -0,0 +1,13 @@ +// pch.h: This is a precompiled header file. +// Files listed below are compiled only once, improving build performance for future builds. +// This also affects IntelliSense performance, including code completion and many code browsing features. +// However, files listed here are ALL re-compiled if any one of them is updated between builds. +// Do not add files here that you will be updating frequently as this negates the performance advantage. + +#ifndef PCH_H +#define PCH_H + +// add headers that you want to pre-compile here +#include "framework.h" + +#endif //PCH_H diff --git a/galliumhook/minhook-multihook/.editorconfig b/galliumhook/minhook-multihook/.editorconfig new file mode 100644 index 0000000..36c09e6 --- /dev/null +++ b/galliumhook/minhook-multihook/.editorconfig @@ -0,0 +1,22 @@ +# EditorConfig is awesome: http://EditorConfig.org + +# top-most EditorConfig file +root = true + +# Windows-style newlines with a newline ending every file +[*] +end_of_line = crlf +insert_final_newline = true + +# 4 space indentation +[*.{c,h,def}] +indent_style = space +indent_size = 4 + +# Trim trailing whitespaces +[*.{c,h,def,txt}] +trim_trailing_whitespace = true + +# UTF-8 with BOM +[*.{c,h,def,txt}] +charset=utf-8-bom diff --git a/galliumhook/minhook-multihook/.gitignore b/galliumhook/minhook-multihook/.gitignore new file mode 100644 index 0000000..ad165d5 --- /dev/null +++ b/galliumhook/minhook-multihook/.gitignore @@ -0,0 +1,44 @@ +#OS junk files +[Tt]humbs.db +*.DS_Store + +#Visual Studio files +*.[Oo]bj +*.user +*.aps +*.pch +*.vspscc +*.vssscc +*_i.c +*_p.c +*.ncb +*.suo +*.tlb +*.tlh +*.bak +*.[Cc]ache +*.ilk +*.log +*.sbr +*.sdf +*.opensdf +*.unsuccessfulbuild +ipch/ +obj/ +[Ll]ib +[Bb]in +[Dd]ebug*/ +[Rr]elease*/ +Ankh.NoLoad +*.VC.db +.vs/ + +#GCC files +*.o +*.d +*.res +*.dll +*.a + +#Visual Studio Code files +.vscode/ diff --git a/galliumhook/minhook-multihook/AUTHORS.txt b/galliumhook/minhook-multihook/AUTHORS.txt new file mode 100644 index 0000000..ebef1a6 --- /dev/null +++ b/galliumhook/minhook-multihook/AUTHORS.txt @@ -0,0 +1,8 @@ +Tsuda Kageyu + Creator, maintainer + +Michael Maltsev + Added "Queue" functions. A lot of bug fixes. + +Andrey Unis + Rewrote the hook engine in plain C. diff --git a/galliumhook/minhook-multihook/CMakeLists.txt b/galliumhook/minhook-multihook/CMakeLists.txt new file mode 100644 index 0000000..df947af --- /dev/null +++ b/galliumhook/minhook-multihook/CMakeLists.txt @@ -0,0 +1,141 @@ +# MinHook - The Minimalistic API Hooking Library for x64/x86 +# Copyright (C) 2009-2017 Tsuda Kageyu. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER +# OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +cmake_minimum_required(VERSION 3.0) + +project(minhook LANGUAGES C) + +include(CMakePackageConfigHelpers) + +set(MINHOOK_MAJOR_VERSION 1) +set(MINHOOK_MINOR_VERSION 3) +set(MINHOOK_PATCH_VERSION 3) +set(MINHOOK_VERSION ${MINHOOK_MAJOR_VERSION}.${MINHOOK_MINOR_VERSION}.${MINHOOK_PATCH_VERSION}) + +################ +# BUILD # +################ + +option(BUILD_SHARED_LIBS "build shared version" OFF) + +set(SOURCES_MINHOOK + "src/buffer.c" + "src/hook.c" + "src/trampoline.c" +) + +if(CMAKE_SIZEOF_VOID_P EQUAL 8) + set(SOURCES_HDE "src/hde/hde64.c") +else() + set(SOURCES_HDE "src/hde/hde32.c") +endif() + +if(BUILD_SHARED_LIBS) + set(RESOURCES + "dll_resources/minhook.rc" + "dll_resources/minhook.def" + ) +endif() + +add_library(minhook ${SOURCES_MINHOOK} ${SOURCES_HDE} ${RESOURCES}) + +target_include_directories(minhook PUBLIC + $ + $ +) + +target_include_directories(minhook PRIVATE "src/") +target_include_directories(minhook PRIVATE "src/hde/") + +if(WIN32) + set_target_properties(minhook PROPERTIES PREFIX "") + if(CMAKE_SIZEOF_VOID_P EQUAL 8) + set_target_properties(minhook PROPERTIES DEBUG_POSTFIX ".x64d") + set_target_properties(minhook PROPERTIES RELEASE_POSTFIX ".x64") + set_target_properties(minhook PROPERTIES RELWITHDEBINFO_POSTFIX ".x64") + set_target_properties(minhook PROPERTIES MINSIZEREL_POSTFIX ".x64") + else() + set_target_properties(minhook PROPERTIES DEBUG_POSTFIX ".x32d") + set_target_properties(minhook PROPERTIES RELEASE_POSTFIX ".x32") + set_target_properties(minhook PROPERTIES RELWITHDEBINFO_POSTFIX ".x32") + set_target_properties(minhook PROPERTIES MINSIZEREL_POSTFIX ".x64") + endif() +else() + set_target_properties(minhook PROPERTIES PREFIX "lib") + set_target_properties(minhook PROPERTIES POSTFIX "") + set_target_properties(minhook PROPERTIES DEBUG_POSTFIX "d") +endif() + +################ +# CMAKE CONFIG # +################ + +configure_package_config_file( + "cmake/minhook-config.cmake.in" + "minhook-config.cmake" + INSTALL_DESTINATION + "lib/minhook" +) + +write_basic_package_version_file( + "minhook-config-version.cmake" +VERSION + ${MINHOOK_VERSION} +COMPATIBILITY + AnyNewerVersion +) + +install( + FILES + "${CMAKE_CURRENT_BINARY_DIR}/minhook-config.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/minhook-config-version.cmake" + DESTINATION + "lib/minhook" +) + +################### +# INSTALL # +################### + +install(TARGETS minhook + EXPORT minhook-targets + RUNTIME DESTINATION "bin" + ARCHIVE DESTINATION "lib" + LIBRARY DESTINATION "lib" +) + +install( + EXPORT + minhook-targets + NAMESPACE + minhook:: + DESTINATION + "lib/minhook" +) + +install( + DIRECTORY include DESTINATION . +) diff --git a/galliumhook/minhook-multihook/LICENSE.txt b/galliumhook/minhook-multihook/LICENSE.txt new file mode 100644 index 0000000..74dea27 --- /dev/null +++ b/galliumhook/minhook-multihook/LICENSE.txt @@ -0,0 +1,81 @@ +MinHook - The Minimalistic API Hooking Library for x64/x86 +Copyright (C) 2009-2017 Tsuda Kageyu. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER +OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +================================================================================ +Portions of this software are Copyright (c) 2008-2009, Vyacheslav Patkov. +================================================================================ +Hacker Disassembler Engine 32 C +Copyright (c) 2008-2009, Vyacheslav Patkov. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +------------------------------------------------------------------------------- +Hacker Disassembler Engine 64 C +Copyright (c) 2008-2009, Vyacheslav Patkov. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/galliumhook/minhook-multihook/README.md b/galliumhook/minhook-multihook/README.md new file mode 100644 index 0000000..99a5d7e --- /dev/null +++ b/galliumhook/minhook-multihook/README.md @@ -0,0 +1,97 @@ +# About the `multihook` branch + +This branch supports hooking the same function from multiple instances of MinHook, as well as hooking the same function more than once from a single MinHook instance. In addition to the new enhancements, it has a couple of new limitations: + +* The original function pointer, returned from `MH_CreateHook`, can only be called when the hook is enabled. +* The `MH_Initialize`, `MH_Uninitialize` functions are not thread safe anymore. +* A mutex object is used for synchronization, and thus a new error code was introduced, `MH_ERROR_MUTEX_FAILURE`. + +You can see a simple demo [here](https://github.com/RaMMicHaeL/minhook-multihook-demo). + +# MinHook + +[![License](https://img.shields.io/badge/License-BSD%202--Clause-orange.svg)](https://opensource.org/licenses/BSD-2-Clause) + +The Minimalistic x86/x64 API Hooking Library for Windows + +http://www.codeproject.com/KB/winsdk/LibMinHook.aspx + +### Version history + +- **v1.3.3 - 8 Jan 2017** + * Added a helper function ```MH_CreateHookApiEx```. (Thanks to asm256) + * Support Visual Studio 2017 RC. + +- **v1.3.2.1 - 9 Nov 2015** (Nuget package only) + * Fixed an insufficient support for Visual Studio 2015. + +- **v1.3.2 - 1 Nov 2015** + * Support Visual Studio 2015. + * Support MinGW. + +- **v1.3.2-beta3 - 21 Jul 2015** (Nuget package only) + * Support MinGW. (Experimental) + +- **v1.3.2-beta2 - 18 May 2015** + * Fixed some subtle bugs. (Thanks to RaMMicHaeL) + * Added a helper function ```MH_StatusToString```. (Thanks to Jan Klass) + +- **v1.3.2-beta - 12 May 2015** + * Fixed a possible thread deadlock in x64 mode. (Thanks to Aleh Kazakevich) + * Reduced the footprint a little more. + * Support Visual Studio 2015 RC. (Experimental) + +- **v1.3.1.1 - 7 Apr 2015** (Nuget package only) + * Support for WDK8.0 and 8.1. + +- **v1.3.1 - 19 Mar 2015** + * No major changes from v1.3.1-beta. + +- **v1.3.1-beta - 11 Mar 2015** + * Added a helper function ```MH_CreateHookApi```. (Thanks to uniskz). + * Fixed a false memory leak reported by some tools. + * Fixed a degradated compatibility issue. + +- **v1.3 - 13 Sep 2014** + * No major changes from v1.3-beta3. + +- **v1.3-beta3 - 31 Jul 2014** + * Fixed some small bugs. + * Improved the memory management. + +- **v1.3-beta2 - 21 Jul 2014** + * Changed the parameters to Windows-friendly types. (void* to LPVOID) + * Fixed some small bugs. + * Reorganized the source files. + * Reduced the footprint a little more. + +- **v1.3-beta - 17 Jul 2014** + * Rewrote in plain C to reduce the footprint and memory usage. (suggested by Andrey Unis) + * Simplified the overall code base to make it more readable and maintainable. + * Changed the license from 3-clause to 2-clause BSD License. + +- **v1.2 - 28 Sep 2013** + * Removed boost dependency ([jarredholman](https://github.com/jarredholman/minhook)). + * Fixed a small bug in the GetRelativeBranchDestination function ([pillbug99](http://www.codeproject.com/Messages/4058892/Small-Bug-Found.aspx)). + * Added the ```MH_RemoveHook``` function, which removes a hook created with the ```MH_CreateHook``` function. + * Added the following functions to enable or disable multiple hooks in one go: ```MH_QueueEnableHook```, ```MH_QueueDisableHook```, ```MH_ApplyQueued```. This is the preferred way of handling multiple hooks as every call to `MH_EnableHook` or `MH_DisableHook` suspends and resumes all threads. + * Made the functions ```MH_EnableHook``` and ```MH_DisableHook``` enable/disable all created hooks when the ```MH_ALL_HOOKS``` parameter is passed. This, too, is an efficient way of handling multiple hooks. + * If the target function is too small to be patched with a jump, MinHook tries to place the jump above the function. If that fails as well, the ```MH_CreateHook``` function returns ```MH_ERROR_UNSUPPORTED_FUNCTION```. This fixes an issue of hooking the LoadLibraryExW function on Windows 7 x64 ([reported by Obble](http://www.codeproject.com/Messages/4578613/Re-Bug-LoadLibraryExW-hook-fails-on-windows-2008-r.aspx)). + +- **v1.1 - 26 Nov 2009** + * Changed the interface to create a hook and a trampoline function in one go to prevent the detour function from being called before the trampoline function is created. ([reported by xliqz](http://www.codeproject.com/Messages/3280374/Unsafe.aspx)) + * Shortened the function names from ```MinHook_*``` to ```MH_*``` to make them handier. + +- **v1.0 - 22 Nov 2009** + * Initial release. + +### Building MinHook - Using vcpkg + +You can download and install MinHook using the [vcpkg](https://github.com/Microsoft/vcpkg) dependency manager: + + git clone https://github.com/microsoft/vcpkg + .\vcpkg\bootstrap-vcpkg.bat + .\vcpkg\vcpkg integrate install + .\vcpkg\vcpkg install minhook + +The MinHook port in vcpkg is kept up to date by Microsoft team members and community contributors. If the version is out of date, please [create an issue or pull request](https://github.com/Microsoft/vcpkg) on the vcpkg repository. diff --git a/galliumhook/minhook-multihook/build/MinGW/Makefile b/galliumhook/minhook-multihook/build/MinGW/Makefile new file mode 100644 index 0000000..cc16725 --- /dev/null +++ b/galliumhook/minhook-multihook/build/MinGW/Makefile @@ -0,0 +1,33 @@ +WINDRES:=$(CROSS_PREFIX)windres +DLLTOOL:=$(CROSS_PREFIX)dlltool +AR:=$(CROSS_PREFIX)ar +CC:=$(CROSS_PREFIX)gcc +CCLD:=$(CC) +SRCS:=$(wildcard src/*.c src/hde/*.c) +OBJS:=$(SRCS:%.c=%.o) +DEPS:=$(SRCS:%.c=%.d) +INCS:=-Isrc -Iinclude +CFLAGS:=-masm=intel -Wall -Werror -std=c11 +LDFLAGS:=-Wl,-enable-stdcall-fixup -s -static-libgcc + +all: MinHook.dll libMinHook.dll.a libMinHook.a + +-include $(DEPS) + +libMinHook.a: $(OBJS) + $(AR) r $@ $^ +libMinHook.dll.a: MinHook.dll dll_resources/MinHook.def + $(DLLTOOL) --dllname MinHook.dll --def dll_resources/MinHook.def --output-lib $@ +MinHook.dll: $(OBJS) dll_resources/MinHook.res dll_resources/MinHook.def + $(CCLD) -o $@ -shared $(LDFLAGS) $^ + +.rc.res: + $(WINDRES) -o $@ --input-format=rc --output-format=coff $< +.c.o: + $(CC) -o $@ -c -MMD -MP $(INCS) $(CFLAGS) $< + +clean: + rm -f $(OBJS) $(DEPS) MinHook.dll libMinHook.dll.a libMinHook.a dll_resources/MinHook.res + +.PHONY: clean +.SUFFIXES: .rc .res diff --git a/galliumhook/minhook-multihook/build/MinGW/make.bat b/galliumhook/minhook-multihook/build/MinGW/make.bat new file mode 100644 index 0000000..7671878 --- /dev/null +++ b/galliumhook/minhook-multihook/build/MinGW/make.bat @@ -0,0 +1 @@ +windres -i ../../dll_resources/MinHook.rc -o MinHook_rc.o && dllwrap --driver-name g++ -o MinHook.dll -masm=intel --def ../../dll_resources/MinHook.def -Wl,-enable-stdcall-fixup -Wall MinHook_rc.o ../../src/*.c ../../src/HDE/*.c -I../../include -I../../src -Werror -std=c++11 -s -static-libgcc -static-libstdc++|| pause \ No newline at end of file diff --git a/galliumhook/minhook-multihook/build/VC10/MinHook.vcxproj b/galliumhook/minhook-multihook/build/VC10/MinHook.vcxproj new file mode 100644 index 0000000..3944d80 --- /dev/null +++ b/galliumhook/minhook-multihook/build/VC10/MinHook.vcxproj @@ -0,0 +1,189 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {027FAC75-3FDB-4044-8DD0-BC297BD4C461} + MinHook + Win32Proj + + + + DynamicLibrary + Unicode + true + + + DynamicLibrary + Unicode + + + DynamicLibrary + Unicode + true + + + DynamicLibrary + Unicode + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.40219.1 + $(SolutionDir)bin\$(Configuration)\ + $(Platform)\$(Configuration)\$(ProjectName)\ + true + $(SolutionDir)bin\$(Configuration)\ + $(Platform)\$(Configuration)\$(ProjectName)\ + true + $(SolutionDir)bin\$(Configuration)\ + $(Platform)\$(Configuration)\$(ProjectName)\ + false + $(SolutionDir)bin\$(Configuration)\ + $(Platform)\$(Configuration)\$(ProjectName)\ + false + $(ProjectName).x86 + $(ProjectName).x86 + $(ProjectName).x64 + $(ProjectName).x64 + + + + Disabled + WIN32;_DEBUG;_WINDOWS;_USRDLL;MINHOOK_EXPORTS;%(PreprocessorDefinitions) + false + EnableFastChecks + MultiThreadedDebug + + + Level3 + + + + + $(SolutionDir)..\..\dll_resources\MinHook.def + false + Windows + MachineX86 + $(SolutionDir)lib\$(Configuration)\libMinHook.x86.lib;%(AdditionalDependencies) + + + + + X64 + + + Disabled + WIN32;_DEBUG;_WINDOWS;_USRDLL;MINHOOK_EXPORTS;%(PreprocessorDefinitions) + false + EnableFastChecks + MultiThreadedDebug + + + Level3 + + + + + $(SolutionDir)..\..\dll_resources\MinHook.def + false + Windows + MachineX64 + $(SolutionDir)lib\$(Configuration)\libMinHook.x64.lib;%(AdditionalDependencies) + + + + + MinSpace + true + WIN32;NDEBUG;_WINDOWS;_USRDLL;MINHOOK_EXPORTS;%(PreprocessorDefinitions) + MultiThreaded + true + + + Level3 + + + false + + + $(SolutionDir)..\..\dll_resources\MinHook.def + false + Windows + true + true + MachineX86 + $(SolutionDir)lib\$(Configuration)\libMinHook.x86.lib;%(AdditionalDependencies) + true + .CRT=.text + + + + + X64 + + + MinSpace + true + WIN32;NDEBUG;_WINDOWS;_USRDLL;MINHOOK_EXPORTS;%(PreprocessorDefinitions) + MultiThreaded + true + + + Level3 + + + false + + + $(SolutionDir)..\..\dll_resources\MinHook.def + false + Windows + true + true + MachineX64 + $(SolutionDir)lib\$(Configuration)\libMinHook.x64.lib;%(AdditionalDependencies) + true + .CRT=.text + + + + + + + + + + + + \ No newline at end of file diff --git a/galliumhook/minhook-multihook/build/VC10/MinHookVC10.sln b/galliumhook/minhook-multihook/build/VC10/MinHookVC10.sln new file mode 100644 index 0000000..dcc1d5c --- /dev/null +++ b/galliumhook/minhook-multihook/build/VC10/MinHookVC10.sln @@ -0,0 +1,39 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libMinHook", "libMinHook.vcxproj", "{F142A341-5EE0-442D-A15F-98AE9B48DBAE}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MinHook", "MinHook.vcxproj", "{027FAC75-3FDB-4044-8DD0-BC297BD4C461}" + ProjectSection(ProjectDependencies) = postProject + {F142A341-5EE0-442D-A15F-98AE9B48DBAE} = {F142A341-5EE0-442D-A15F-98AE9B48DBAE} + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {F142A341-5EE0-442D-A15F-98AE9B48DBAE}.Debug|Win32.ActiveCfg = Debug|Win32 + {F142A341-5EE0-442D-A15F-98AE9B48DBAE}.Debug|Win32.Build.0 = Debug|Win32 + {F142A341-5EE0-442D-A15F-98AE9B48DBAE}.Debug|x64.ActiveCfg = Debug|x64 + {F142A341-5EE0-442D-A15F-98AE9B48DBAE}.Debug|x64.Build.0 = Debug|x64 + {F142A341-5EE0-442D-A15F-98AE9B48DBAE}.Release|Win32.ActiveCfg = Release|Win32 + {F142A341-5EE0-442D-A15F-98AE9B48DBAE}.Release|Win32.Build.0 = Release|Win32 + {F142A341-5EE0-442D-A15F-98AE9B48DBAE}.Release|x64.ActiveCfg = Release|x64 + {F142A341-5EE0-442D-A15F-98AE9B48DBAE}.Release|x64.Build.0 = Release|x64 + {027FAC75-3FDB-4044-8DD0-BC297BD4C461}.Debug|Win32.ActiveCfg = Debug|Win32 + {027FAC75-3FDB-4044-8DD0-BC297BD4C461}.Debug|Win32.Build.0 = Debug|Win32 + {027FAC75-3FDB-4044-8DD0-BC297BD4C461}.Debug|x64.ActiveCfg = Debug|x64 + {027FAC75-3FDB-4044-8DD0-BC297BD4C461}.Debug|x64.Build.0 = Debug|x64 + {027FAC75-3FDB-4044-8DD0-BC297BD4C461}.Release|Win32.ActiveCfg = Release|Win32 + {027FAC75-3FDB-4044-8DD0-BC297BD4C461}.Release|Win32.Build.0 = Release|Win32 + {027FAC75-3FDB-4044-8DD0-BC297BD4C461}.Release|x64.ActiveCfg = Release|x64 + {027FAC75-3FDB-4044-8DD0-BC297BD4C461}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/galliumhook/minhook-multihook/build/VC10/libMinHook.vcxproj b/galliumhook/minhook-multihook/build/VC10/libMinHook.vcxproj new file mode 100644 index 0000000..589ff9a --- /dev/null +++ b/galliumhook/minhook-multihook/build/VC10/libMinHook.vcxproj @@ -0,0 +1,172 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {F142A341-5EE0-442D-A15F-98AE9B48DBAE} + libMinHook + Win32Proj + + + + StaticLibrary + Unicode + true + + + StaticLibrary + Unicode + + + StaticLibrary + Unicode + true + + + StaticLibrary + Unicode + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.40219.1 + $(SolutionDir)lib\$(Configuration)\ + $(Platform)\$(Configuration)\$(ProjectName)\ + $(SolutionDir)lib\$(Configuration)\ + $(Platform)\$(Configuration)\$(ProjectName)\ + $(SolutionDir)lib\$(Configuration)\ + $(Platform)\$(Configuration)\$(ProjectName)\ + $(SolutionDir)lib\$(Configuration)\ + $(Platform)\$(Configuration)\$(ProjectName)\ + $(ProjectName).x86 + $(ProjectName).x86 + $(ProjectName).x64 + $(ProjectName).x64 + + + + Disabled + %(AdditionalIncludeDirectories) + WIN32;_DEBUG;_LIB;STRICT;%(PreprocessorDefinitions) + false + EnableFastChecks + MultiThreadedDebug + Level3 + + + false + + + + + + X64 + + + Disabled + %(AdditionalIncludeDirectories) + WIN32;_DEBUG;_LIB;STRICT;%(PreprocessorDefinitions) + false + EnableFastChecks + MultiThreadedDebug + Level3 + + + false + + + + + + MinSpace + true + %(AdditionalIncludeDirectories) + WIN32;NDEBUG;_LIB;STRICT;%(PreprocessorDefinitions) + false + MultiThreaded + true + Level3 + + + true + AnySuitable + + + + + + X64 + + + MinSpace + true + %(AdditionalIncludeDirectories) + WIN32;NDEBUG;_LIB;STRICT;%(PreprocessorDefinitions) + false + MultiThreaded + true + Level3 + + + true + AnySuitable + + + + + + + true + true + + + true + true + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/galliumhook/minhook-multihook/build/VC10/libMinHook.vcxproj.filters b/galliumhook/minhook-multihook/build/VC10/libMinHook.vcxproj.filters new file mode 100644 index 0000000..f2d1d97 --- /dev/null +++ b/galliumhook/minhook-multihook/build/VC10/libMinHook.vcxproj.filters @@ -0,0 +1,55 @@ + + + + + Source Files + + + Source Files + + + Source Files + + + HDE + + + HDE + + + + + Header Files + + + Header Files + + + + HDE + + + HDE + + + HDE + + + HDE + + + HDE + + + + + {9d24b740-be2e-4cfd-b9a4-340a50946ee9} + + + {76381bc7-2863-4cc5-aede-926ec2c506e4} + + + {56ddb326-6179-430d-ae19-e13bfd767bfa} + + + \ No newline at end of file diff --git a/galliumhook/minhook-multihook/build/VC11/MinHook.vcxproj b/galliumhook/minhook-multihook/build/VC11/MinHook.vcxproj new file mode 100644 index 0000000..4c0e212 --- /dev/null +++ b/galliumhook/minhook-multihook/build/VC11/MinHook.vcxproj @@ -0,0 +1,189 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {027FAC75-3FDB-4044-8DD0-BC297BD4C461} + MinHook + Win32Proj + + + + DynamicLibrary + Unicode + true + v110_xp + + + DynamicLibrary + Unicode + v110_xp + + + DynamicLibrary + Unicode + true + v110_xp + + + DynamicLibrary + Unicode + v110_xp + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.40219.1 + $(SolutionDir)bin\$(Configuration)\ + $(Platform)\$(Configuration)\$(ProjectName)\ + true + $(SolutionDir)bin\$(Configuration)\ + $(Platform)\$(Configuration)\$(ProjectName)\ + true + $(SolutionDir)bin\$(Configuration)\ + $(Platform)\$(Configuration)\$(ProjectName)\ + false + $(SolutionDir)bin\$(Configuration)\ + $(Platform)\$(Configuration)\$(ProjectName)\ + false + $(ProjectName).x86 + $(ProjectName).x86 + $(ProjectName).x64 + $(ProjectName).x64 + + + + Disabled + WIN32;_DEBUG;_WINDOWS;_USRDLL;MINHOOK_EXPORTS;%(PreprocessorDefinitions) + false + EnableFastChecks + MultiThreadedDebug + + + Level3 + None + + + $(SolutionDir)..\..\dll_resources\MinHook.def + false + Windows + MachineX86 + $(SolutionDir)lib\$(Configuration)\libMinHook.x86.lib;%(AdditionalDependencies) + + + + + X64 + + + Disabled + WIN32;_DEBUG;_WINDOWS;_USRDLL;MINHOOK_EXPORTS;%(PreprocessorDefinitions) + false + EnableFastChecks + MultiThreadedDebug + + + Level3 + None + + + $(SolutionDir)..\..\dll_resources\MinHook.def + false + Windows + MachineX64 + $(SolutionDir)lib\$(Configuration)\libMinHook.x64.lib;%(AdditionalDependencies) + + + + + MinSpace + true + WIN32;NDEBUG;_WINDOWS;_USRDLL;MINHOOK_EXPORTS;%(PreprocessorDefinitions) + MultiThreaded + true + + + Level3 + None + false + + + $(SolutionDir)..\..\dll_resources\MinHook.def + false + Windows + true + true + MachineX86 + $(SolutionDir)lib\$(Configuration)\libMinHook.x86.lib;%(AdditionalDependencies) + true + .CRT=.text + + + + + X64 + + + MinSpace + true + WIN32;NDEBUG;_WINDOWS;_USRDLL;MINHOOK_EXPORTS;%(PreprocessorDefinitions) + MultiThreaded + true + + + Level3 + None + false + + + $(SolutionDir)..\..\dll_resources\MinHook.def + false + Windows + true + true + MachineX64 + $(SolutionDir)lib\$(Configuration)\libMinHook.x64.lib;%(AdditionalDependencies) + true + .CRT=.text + + + + + + + + + + + + \ No newline at end of file diff --git a/galliumhook/minhook-multihook/build/VC11/MinHookVC11.sln b/galliumhook/minhook-multihook/build/VC11/MinHookVC11.sln new file mode 100644 index 0000000..5b56553 --- /dev/null +++ b/galliumhook/minhook-multihook/build/VC11/MinHookVC11.sln @@ -0,0 +1,39 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2012 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libMinHook", "libMinHook.vcxproj", "{F142A341-5EE0-442D-A15F-98AE9B48DBAE}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MinHook", "MinHook.vcxproj", "{027FAC75-3FDB-4044-8DD0-BC297BD4C461}" + ProjectSection(ProjectDependencies) = postProject + {F142A341-5EE0-442D-A15F-98AE9B48DBAE} = {F142A341-5EE0-442D-A15F-98AE9B48DBAE} + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {F142A341-5EE0-442D-A15F-98AE9B48DBAE}.Debug|Win32.ActiveCfg = Debug|Win32 + {F142A341-5EE0-442D-A15F-98AE9B48DBAE}.Debug|Win32.Build.0 = Debug|Win32 + {F142A341-5EE0-442D-A15F-98AE9B48DBAE}.Debug|x64.ActiveCfg = Debug|x64 + {F142A341-5EE0-442D-A15F-98AE9B48DBAE}.Debug|x64.Build.0 = Debug|x64 + {F142A341-5EE0-442D-A15F-98AE9B48DBAE}.Release|Win32.ActiveCfg = Release|Win32 + {F142A341-5EE0-442D-A15F-98AE9B48DBAE}.Release|Win32.Build.0 = Release|Win32 + {F142A341-5EE0-442D-A15F-98AE9B48DBAE}.Release|x64.ActiveCfg = Release|x64 + {F142A341-5EE0-442D-A15F-98AE9B48DBAE}.Release|x64.Build.0 = Release|x64 + {027FAC75-3FDB-4044-8DD0-BC297BD4C461}.Debug|Win32.ActiveCfg = Debug|Win32 + {027FAC75-3FDB-4044-8DD0-BC297BD4C461}.Debug|Win32.Build.0 = Debug|Win32 + {027FAC75-3FDB-4044-8DD0-BC297BD4C461}.Debug|x64.ActiveCfg = Debug|x64 + {027FAC75-3FDB-4044-8DD0-BC297BD4C461}.Debug|x64.Build.0 = Debug|x64 + {027FAC75-3FDB-4044-8DD0-BC297BD4C461}.Release|Win32.ActiveCfg = Release|Win32 + {027FAC75-3FDB-4044-8DD0-BC297BD4C461}.Release|Win32.Build.0 = Release|Win32 + {027FAC75-3FDB-4044-8DD0-BC297BD4C461}.Release|x64.ActiveCfg = Release|x64 + {027FAC75-3FDB-4044-8DD0-BC297BD4C461}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/galliumhook/minhook-multihook/build/VC11/libMinHook.vcxproj b/galliumhook/minhook-multihook/build/VC11/libMinHook.vcxproj new file mode 100644 index 0000000..1a65499 --- /dev/null +++ b/galliumhook/minhook-multihook/build/VC11/libMinHook.vcxproj @@ -0,0 +1,172 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {F142A341-5EE0-442D-A15F-98AE9B48DBAE} + libMinHook + Win32Proj + + + + StaticLibrary + Unicode + true + v110_xp + + + StaticLibrary + Unicode + v110_xp + + + StaticLibrary + Unicode + true + v110_xp + + + StaticLibrary + Unicode + v110_xp + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.40219.1 + $(SolutionDir)lib\$(Configuration)\ + $(Platform)\$(Configuration)\$(ProjectName)\ + $(SolutionDir)lib\$(Configuration)\ + $(Platform)\$(Configuration)\$(ProjectName)\ + $(SolutionDir)lib\$(Configuration)\ + $(Platform)\$(Configuration)\$(ProjectName)\ + $(SolutionDir)lib\$(Configuration)\ + $(Platform)\$(Configuration)\$(ProjectName)\ + $(ProjectName).x86 + $(ProjectName).x86 + $(ProjectName).x64 + $(ProjectName).x64 + + + + Disabled + %(AdditionalIncludeDirectories) + WIN32;_DEBUG;_LIB;STRICT;%(PreprocessorDefinitions) + false + EnableFastChecks + MultiThreadedDebug + Level3 + None + NoExtensions + + + + + + X64 + + + Disabled + %(AdditionalIncludeDirectories) + WIN32;_DEBUG;_LIB;STRICT;%(PreprocessorDefinitions) + false + EnableFastChecks + MultiThreadedDebug + Level3 + None + + + + + + MinSpace + true + %(AdditionalIncludeDirectories) + WIN32;NDEBUG;_LIB;STRICT;%(PreprocessorDefinitions) + false + MultiThreaded + true + Level3 + None + true + AnySuitable + NoExtensions + + + + + + X64 + + + MinSpace + true + %(AdditionalIncludeDirectories) + WIN32;NDEBUG;_LIB;STRICT;%(PreprocessorDefinitions) + false + MultiThreaded + true + Level3 + None + true + AnySuitable + + + + + + + true + true + + + true + true + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/galliumhook/minhook-multihook/build/VC11/libMinHook.vcxproj.filters b/galliumhook/minhook-multihook/build/VC11/libMinHook.vcxproj.filters new file mode 100644 index 0000000..f2d1d97 --- /dev/null +++ b/galliumhook/minhook-multihook/build/VC11/libMinHook.vcxproj.filters @@ -0,0 +1,55 @@ + + + + + Source Files + + + Source Files + + + Source Files + + + HDE + + + HDE + + + + + Header Files + + + Header Files + + + + HDE + + + HDE + + + HDE + + + HDE + + + HDE + + + + + {9d24b740-be2e-4cfd-b9a4-340a50946ee9} + + + {76381bc7-2863-4cc5-aede-926ec2c506e4} + + + {56ddb326-6179-430d-ae19-e13bfd767bfa} + + + \ No newline at end of file diff --git a/galliumhook/minhook-multihook/build/VC12/MinHook.vcxproj b/galliumhook/minhook-multihook/build/VC12/MinHook.vcxproj new file mode 100644 index 0000000..40ec836 --- /dev/null +++ b/galliumhook/minhook-multihook/build/VC12/MinHook.vcxproj @@ -0,0 +1,189 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {027FAC75-3FDB-4044-8DD0-BC297BD4C461} + MinHook + Win32Proj + + + + DynamicLibrary + Unicode + true + v120_xp + + + DynamicLibrary + Unicode + v120_xp + + + DynamicLibrary + Unicode + true + v120_xp + + + DynamicLibrary + Unicode + v120_xp + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.40219.1 + $(SolutionDir)bin\$(Configuration)\ + $(Platform)\$(Configuration)\$(ProjectName)\ + true + $(SolutionDir)bin\$(Configuration)\ + $(Platform)\$(Configuration)\$(ProjectName)\ + true + $(SolutionDir)bin\$(Configuration)\ + $(Platform)\$(Configuration)\$(ProjectName)\ + false + $(SolutionDir)bin\$(Configuration)\ + $(Platform)\$(Configuration)\$(ProjectName)\ + false + $(ProjectName).x86 + $(ProjectName).x86 + $(ProjectName).x64 + $(ProjectName).x64 + + + + Disabled + WIN32;_DEBUG;_WINDOWS;_USRDLL;MINHOOK_EXPORTS;%(PreprocessorDefinitions) + false + EnableFastChecks + MultiThreadedDebug + + + Level3 + None + + + $(SolutionDir)..\..\dll_resources\MinHook.def + false + Windows + MachineX86 + $(SolutionDir)lib\$(Configuration)\libMinHook.x86.lib;%(AdditionalDependencies) + + + + + X64 + + + Disabled + WIN32;_DEBUG;_WINDOWS;_USRDLL;MINHOOK_EXPORTS;%(PreprocessorDefinitions) + false + EnableFastChecks + MultiThreadedDebug + + + Level3 + None + + + $(SolutionDir)..\..\dll_resources\MinHook.def + false + Windows + MachineX64 + $(SolutionDir)lib\$(Configuration)\libMinHook.x64.lib;%(AdditionalDependencies) + + + + + MinSpace + true + WIN32;NDEBUG;_WINDOWS;_USRDLL;MINHOOK_EXPORTS;%(PreprocessorDefinitions) + MultiThreaded + true + + + Level3 + None + false + + + $(SolutionDir)..\..\dll_resources\MinHook.def + false + Windows + true + true + MachineX86 + $(SolutionDir)lib\$(Configuration)\libMinHook.x86.lib;%(AdditionalDependencies) + true + .CRT=.text + + + + + X64 + + + MinSpace + true + WIN32;NDEBUG;_WINDOWS;_USRDLL;MINHOOK_EXPORTS;%(PreprocessorDefinitions) + MultiThreaded + true + + + Level3 + None + false + + + $(SolutionDir)..\..\dll_resources\MinHook.def + false + Windows + true + true + MachineX64 + $(SolutionDir)lib\$(Configuration)\libMinHook.x64.lib;%(AdditionalDependencies) + true + .CRT=.text + + + + + + + + + + + + \ No newline at end of file diff --git a/galliumhook/minhook-multihook/build/VC12/MinHookVC12.sln b/galliumhook/minhook-multihook/build/VC12/MinHookVC12.sln new file mode 100644 index 0000000..cfd928b --- /dev/null +++ b/galliumhook/minhook-multihook/build/VC12/MinHookVC12.sln @@ -0,0 +1,41 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0.30501.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libMinHook", "libMinHook.vcxproj", "{F142A341-5EE0-442D-A15F-98AE9B48DBAE}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MinHook", "MinHook.vcxproj", "{027FAC75-3FDB-4044-8DD0-BC297BD4C461}" + ProjectSection(ProjectDependencies) = postProject + {F142A341-5EE0-442D-A15F-98AE9B48DBAE} = {F142A341-5EE0-442D-A15F-98AE9B48DBAE} + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {F142A341-5EE0-442D-A15F-98AE9B48DBAE}.Debug|Win32.ActiveCfg = Debug|Win32 + {F142A341-5EE0-442D-A15F-98AE9B48DBAE}.Debug|Win32.Build.0 = Debug|Win32 + {F142A341-5EE0-442D-A15F-98AE9B48DBAE}.Debug|x64.ActiveCfg = Debug|x64 + {F142A341-5EE0-442D-A15F-98AE9B48DBAE}.Debug|x64.Build.0 = Debug|x64 + {F142A341-5EE0-442D-A15F-98AE9B48DBAE}.Release|Win32.ActiveCfg = Release|Win32 + {F142A341-5EE0-442D-A15F-98AE9B48DBAE}.Release|Win32.Build.0 = Release|Win32 + {F142A341-5EE0-442D-A15F-98AE9B48DBAE}.Release|x64.ActiveCfg = Release|x64 + {F142A341-5EE0-442D-A15F-98AE9B48DBAE}.Release|x64.Build.0 = Release|x64 + {027FAC75-3FDB-4044-8DD0-BC297BD4C461}.Debug|Win32.ActiveCfg = Debug|Win32 + {027FAC75-3FDB-4044-8DD0-BC297BD4C461}.Debug|Win32.Build.0 = Debug|Win32 + {027FAC75-3FDB-4044-8DD0-BC297BD4C461}.Debug|x64.ActiveCfg = Debug|x64 + {027FAC75-3FDB-4044-8DD0-BC297BD4C461}.Debug|x64.Build.0 = Debug|x64 + {027FAC75-3FDB-4044-8DD0-BC297BD4C461}.Release|Win32.ActiveCfg = Release|Win32 + {027FAC75-3FDB-4044-8DD0-BC297BD4C461}.Release|Win32.Build.0 = Release|Win32 + {027FAC75-3FDB-4044-8DD0-BC297BD4C461}.Release|x64.ActiveCfg = Release|x64 + {027FAC75-3FDB-4044-8DD0-BC297BD4C461}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/galliumhook/minhook-multihook/build/VC12/libMinHook.vcxproj b/galliumhook/minhook-multihook/build/VC12/libMinHook.vcxproj new file mode 100644 index 0000000..7e7fe8e --- /dev/null +++ b/galliumhook/minhook-multihook/build/VC12/libMinHook.vcxproj @@ -0,0 +1,173 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {F142A341-5EE0-442D-A15F-98AE9B48DBAE} + libMinHook + Win32Proj + + + + StaticLibrary + Unicode + true + v120_xp + + + StaticLibrary + Unicode + v120_xp + + + StaticLibrary + Unicode + true + v120_xp + + + StaticLibrary + Unicode + v120_xp + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.40219.1 + $(SolutionDir)lib\$(Configuration)\ + $(Platform)\$(Configuration)\$(ProjectName)\ + $(SolutionDir)lib\$(Configuration)\ + $(Platform)\$(Configuration)\$(ProjectName)\ + $(SolutionDir)lib\$(Configuration)\ + $(Platform)\$(Configuration)\$(ProjectName)\ + $(SolutionDir)lib\$(Configuration)\ + $(Platform)\$(Configuration)\$(ProjectName)\ + $(ProjectName).x86 + $(ProjectName).x86 + $(ProjectName).x64 + $(ProjectName).x64 + + + + Disabled + %(AdditionalIncludeDirectories) + WIN32;_DEBUG;_LIB;STRICT;%(PreprocessorDefinitions) + false + EnableFastChecks + MultiThreadedDebug + Level3 + None + NoExtensions + + + + + + X64 + + + Disabled + %(AdditionalIncludeDirectories) + WIN32;_DEBUG;_LIB;STRICT;%(PreprocessorDefinitions) + false + EnableFastChecks + MultiThreadedDebug + Level3 + None + NotSet + + + + + + MinSpace + true + %(AdditionalIncludeDirectories) + WIN32;NDEBUG;_LIB;STRICT;%(PreprocessorDefinitions) + false + MultiThreaded + true + Level3 + None + AnySuitable + true + NoExtensions + + + + + + X64 + + + MinSpace + true + %(AdditionalIncludeDirectories) + WIN32;NDEBUG;_LIB;STRICT;%(PreprocessorDefinitions) + false + MultiThreaded + true + Level3 + None + true + AnySuitable + + + + + + + true + true + + + true + true + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/galliumhook/minhook-multihook/build/VC12/libMinHook.vcxproj.filters b/galliumhook/minhook-multihook/build/VC12/libMinHook.vcxproj.filters new file mode 100644 index 0000000..f2d1d97 --- /dev/null +++ b/galliumhook/minhook-multihook/build/VC12/libMinHook.vcxproj.filters @@ -0,0 +1,55 @@ + + + + + Source Files + + + Source Files + + + Source Files + + + HDE + + + HDE + + + + + Header Files + + + Header Files + + + + HDE + + + HDE + + + HDE + + + HDE + + + HDE + + + + + {9d24b740-be2e-4cfd-b9a4-340a50946ee9} + + + {76381bc7-2863-4cc5-aede-926ec2c506e4} + + + {56ddb326-6179-430d-ae19-e13bfd767bfa} + + + \ No newline at end of file diff --git a/galliumhook/minhook-multihook/build/VC14/MinHook.vcxproj b/galliumhook/minhook-multihook/build/VC14/MinHook.vcxproj new file mode 100644 index 0000000..d5ecda2 --- /dev/null +++ b/galliumhook/minhook-multihook/build/VC14/MinHook.vcxproj @@ -0,0 +1,189 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {027FAC75-3FDB-4044-8DD0-BC297BD4C461} + MinHook + Win32Proj + + + + DynamicLibrary + Unicode + true + v140_xp + + + DynamicLibrary + Unicode + v140_xp + + + DynamicLibrary + Unicode + true + v140_xp + + + DynamicLibrary + Unicode + v140_xp + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.40219.1 + $(SolutionDir)bin\$(Configuration)\ + $(Platform)\$(Configuration)\$(ProjectName)\ + true + $(SolutionDir)bin\$(Configuration)\ + $(Platform)\$(Configuration)\$(ProjectName)\ + true + $(SolutionDir)bin\$(Configuration)\ + $(Platform)\$(Configuration)\$(ProjectName)\ + false + $(SolutionDir)bin\$(Configuration)\ + $(Platform)\$(Configuration)\$(ProjectName)\ + false + $(ProjectName).x86 + $(ProjectName).x86 + $(ProjectName).x64 + $(ProjectName).x64 + + + + Disabled + WIN32;_DEBUG;_WINDOWS;_USRDLL;MINHOOK_EXPORTS;%(PreprocessorDefinitions) + false + EnableFastChecks + MultiThreadedDebug + + + Level3 + None + + + $(SolutionDir)..\..\dll_resources\MinHook.def + false + Windows + MachineX86 + $(SolutionDir)lib\$(Configuration)\libMinHook.x86.lib;%(AdditionalDependencies) + + + + + X64 + + + Disabled + WIN32;_DEBUG;_WINDOWS;_USRDLL;MINHOOK_EXPORTS;%(PreprocessorDefinitions) + false + EnableFastChecks + MultiThreadedDebug + + + Level3 + None + + + $(SolutionDir)..\..\dll_resources\MinHook.def + false + Windows + MachineX64 + $(SolutionDir)lib\$(Configuration)\libMinHook.x64.lib;%(AdditionalDependencies) + + + + + MinSpace + true + WIN32;NDEBUG;_WINDOWS;_USRDLL;MINHOOK_EXPORTS;%(PreprocessorDefinitions) + MultiThreaded + true + + + Level3 + None + false + + + $(SolutionDir)..\..\dll_resources\MinHook.def + false + Windows + true + true + MachineX86 + $(SolutionDir)lib\$(Configuration)\libMinHook.x86.lib;%(AdditionalDependencies) + true + .CRT=.text + + + + + X64 + + + MinSpace + true + WIN32;NDEBUG;_WINDOWS;_USRDLL;MINHOOK_EXPORTS;%(PreprocessorDefinitions) + MultiThreaded + true + + + Level3 + None + false + + + $(SolutionDir)..\..\dll_resources\MinHook.def + false + Windows + true + true + MachineX64 + $(SolutionDir)lib\$(Configuration)\libMinHook.x64.lib;%(AdditionalDependencies) + true + .CRT=.text + + + + + + + + + + + + \ No newline at end of file diff --git a/galliumhook/minhook-multihook/build/VC14/MinHookVC14.sln b/galliumhook/minhook-multihook/build/VC14/MinHookVC14.sln new file mode 100644 index 0000000..258c192 --- /dev/null +++ b/galliumhook/minhook-multihook/build/VC14/MinHookVC14.sln @@ -0,0 +1,41 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.22823.1 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libMinHook", "libMinHook.vcxproj", "{F142A341-5EE0-442D-A15F-98AE9B48DBAE}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MinHook", "MinHook.vcxproj", "{027FAC75-3FDB-4044-8DD0-BC297BD4C461}" + ProjectSection(ProjectDependencies) = postProject + {F142A341-5EE0-442D-A15F-98AE9B48DBAE} = {F142A341-5EE0-442D-A15F-98AE9B48DBAE} + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {F142A341-5EE0-442D-A15F-98AE9B48DBAE}.Debug|Win32.ActiveCfg = Debug|Win32 + {F142A341-5EE0-442D-A15F-98AE9B48DBAE}.Debug|Win32.Build.0 = Debug|Win32 + {F142A341-5EE0-442D-A15F-98AE9B48DBAE}.Debug|x64.ActiveCfg = Debug|x64 + {F142A341-5EE0-442D-A15F-98AE9B48DBAE}.Debug|x64.Build.0 = Debug|x64 + {F142A341-5EE0-442D-A15F-98AE9B48DBAE}.Release|Win32.ActiveCfg = Release|Win32 + {F142A341-5EE0-442D-A15F-98AE9B48DBAE}.Release|Win32.Build.0 = Release|Win32 + {F142A341-5EE0-442D-A15F-98AE9B48DBAE}.Release|x64.ActiveCfg = Release|x64 + {F142A341-5EE0-442D-A15F-98AE9B48DBAE}.Release|x64.Build.0 = Release|x64 + {027FAC75-3FDB-4044-8DD0-BC297BD4C461}.Debug|Win32.ActiveCfg = Debug|Win32 + {027FAC75-3FDB-4044-8DD0-BC297BD4C461}.Debug|Win32.Build.0 = Debug|Win32 + {027FAC75-3FDB-4044-8DD0-BC297BD4C461}.Debug|x64.ActiveCfg = Debug|x64 + {027FAC75-3FDB-4044-8DD0-BC297BD4C461}.Debug|x64.Build.0 = Debug|x64 + {027FAC75-3FDB-4044-8DD0-BC297BD4C461}.Release|Win32.ActiveCfg = Release|Win32 + {027FAC75-3FDB-4044-8DD0-BC297BD4C461}.Release|Win32.Build.0 = Release|Win32 + {027FAC75-3FDB-4044-8DD0-BC297BD4C461}.Release|x64.ActiveCfg = Release|x64 + {027FAC75-3FDB-4044-8DD0-BC297BD4C461}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/galliumhook/minhook-multihook/build/VC14/libMinHook.vcxproj b/galliumhook/minhook-multihook/build/VC14/libMinHook.vcxproj new file mode 100644 index 0000000..a429e69 --- /dev/null +++ b/galliumhook/minhook-multihook/build/VC14/libMinHook.vcxproj @@ -0,0 +1,173 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {F142A341-5EE0-442D-A15F-98AE9B48DBAE} + libMinHook + Win32Proj + + + + StaticLibrary + Unicode + true + v140_xp + + + StaticLibrary + Unicode + v140_xp + + + StaticLibrary + Unicode + true + v140_xp + + + StaticLibrary + Unicode + v140_xp + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.40219.1 + $(SolutionDir)lib\$(Configuration)\ + $(Platform)\$(Configuration)\$(ProjectName)\ + $(SolutionDir)lib\$(Configuration)\ + $(Platform)\$(Configuration)\$(ProjectName)\ + $(SolutionDir)lib\$(Configuration)\ + $(Platform)\$(Configuration)\$(ProjectName)\ + $(SolutionDir)lib\$(Configuration)\ + $(Platform)\$(Configuration)\$(ProjectName)\ + $(ProjectName).x86 + $(ProjectName).x86 + $(ProjectName).x64 + $(ProjectName).x64 + + + + Disabled + %(AdditionalIncludeDirectories) + WIN32;_DEBUG;_LIB;STRICT;%(PreprocessorDefinitions) + false + EnableFastChecks + MultiThreadedDebug + Level3 + None + NoExtensions + + + + + + X64 + + + Disabled + %(AdditionalIncludeDirectories) + WIN32;_DEBUG;_LIB;STRICT;%(PreprocessorDefinitions) + false + EnableFastChecks + MultiThreadedDebug + Level3 + None + NotSet + + + + + + MinSpace + true + %(AdditionalIncludeDirectories) + WIN32;NDEBUG;_LIB;STRICT;%(PreprocessorDefinitions) + false + MultiThreaded + true + Level3 + None + AnySuitable + true + NoExtensions + + + + + + X64 + + + MinSpace + true + %(AdditionalIncludeDirectories) + WIN32;NDEBUG;_LIB;STRICT;%(PreprocessorDefinitions) + false + MultiThreaded + true + Level3 + None + true + AnySuitable + + + + + + + true + true + + + true + true + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/galliumhook/minhook-multihook/build/VC14/libMinHook.vcxproj.filters b/galliumhook/minhook-multihook/build/VC14/libMinHook.vcxproj.filters new file mode 100644 index 0000000..f2d1d97 --- /dev/null +++ b/galliumhook/minhook-multihook/build/VC14/libMinHook.vcxproj.filters @@ -0,0 +1,55 @@ + + + + + Source Files + + + Source Files + + + Source Files + + + HDE + + + HDE + + + + + Header Files + + + Header Files + + + + HDE + + + HDE + + + HDE + + + HDE + + + HDE + + + + + {9d24b740-be2e-4cfd-b9a4-340a50946ee9} + + + {76381bc7-2863-4cc5-aede-926ec2c506e4} + + + {56ddb326-6179-430d-ae19-e13bfd767bfa} + + + \ No newline at end of file diff --git a/galliumhook/minhook-multihook/build/VC15/MinHook.vcxproj b/galliumhook/minhook-multihook/build/VC15/MinHook.vcxproj new file mode 100644 index 0000000..1d51833 --- /dev/null +++ b/galliumhook/minhook-multihook/build/VC15/MinHook.vcxproj @@ -0,0 +1,189 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {027FAC75-3FDB-4044-8DD0-BC297BD4C461} + MinHook + Win32Proj + + + + DynamicLibrary + Unicode + true + v141_xp + + + DynamicLibrary + Unicode + v141_xp + + + DynamicLibrary + Unicode + true + v141_xp + + + DynamicLibrary + Unicode + v141_xp + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.40219.1 + $(SolutionDir)bin\$(Configuration)\ + $(Platform)\$(Configuration)\$(ProjectName)\ + true + $(SolutionDir)bin\$(Configuration)\ + $(Platform)\$(Configuration)\$(ProjectName)\ + true + $(SolutionDir)bin\$(Configuration)\ + $(Platform)\$(Configuration)\$(ProjectName)\ + false + $(SolutionDir)bin\$(Configuration)\ + $(Platform)\$(Configuration)\$(ProjectName)\ + false + $(ProjectName).x86 + $(ProjectName).x86 + $(ProjectName).x64 + $(ProjectName).x64 + + + + Disabled + WIN32;_DEBUG;_WINDOWS;_USRDLL;MINHOOK_EXPORTS;%(PreprocessorDefinitions) + false + EnableFastChecks + MultiThreadedDebug + + + Level3 + None + + + $(SolutionDir)..\..\dll_resources\MinHook.def + false + Windows + MachineX86 + $(SolutionDir)lib\$(Configuration)\libMinHook.x86.lib;%(AdditionalDependencies) + + + + + X64 + + + Disabled + WIN32;_DEBUG;_WINDOWS;_USRDLL;MINHOOK_EXPORTS;%(PreprocessorDefinitions) + false + EnableFastChecks + MultiThreadedDebug + + + Level3 + None + + + $(SolutionDir)..\..\dll_resources\MinHook.def + false + Windows + MachineX64 + $(SolutionDir)lib\$(Configuration)\libMinHook.x64.lib;%(AdditionalDependencies) + + + + + MinSpace + true + WIN32;NDEBUG;_WINDOWS;_USRDLL;MINHOOK_EXPORTS;%(PreprocessorDefinitions) + MultiThreaded + true + + + Level3 + None + false + + + $(SolutionDir)..\..\dll_resources\MinHook.def + false + Windows + true + true + MachineX86 + $(SolutionDir)lib\$(Configuration)\libMinHook.x86.lib;%(AdditionalDependencies) + true + .CRT=.text + + + + + X64 + + + MinSpace + true + WIN32;NDEBUG;_WINDOWS;_USRDLL;MINHOOK_EXPORTS;%(PreprocessorDefinitions) + MultiThreaded + true + + + Level3 + None + false + + + $(SolutionDir)..\..\dll_resources\MinHook.def + false + Windows + true + true + MachineX64 + $(SolutionDir)lib\$(Configuration)\libMinHook.x64.lib;%(AdditionalDependencies) + true + .CRT=.text + + + + + + + + + + + + diff --git a/galliumhook/minhook-multihook/build/VC15/MinHookVC15.sln b/galliumhook/minhook-multihook/build/VC15/MinHookVC15.sln new file mode 100644 index 0000000..946dc70 --- /dev/null +++ b/galliumhook/minhook-multihook/build/VC15/MinHookVC15.sln @@ -0,0 +1,41 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.25123.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libMinHook", "libMinHook.vcxproj", "{F142A341-5EE0-442D-A15F-98AE9B48DBAE}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MinHook", "MinHook.vcxproj", "{027FAC75-3FDB-4044-8DD0-BC297BD4C461}" + ProjectSection(ProjectDependencies) = postProject + {F142A341-5EE0-442D-A15F-98AE9B48DBAE} = {F142A341-5EE0-442D-A15F-98AE9B48DBAE} + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {F142A341-5EE0-442D-A15F-98AE9B48DBAE}.Debug|Win32.ActiveCfg = Debug|Win32 + {F142A341-5EE0-442D-A15F-98AE9B48DBAE}.Debug|Win32.Build.0 = Debug|Win32 + {F142A341-5EE0-442D-A15F-98AE9B48DBAE}.Debug|x64.ActiveCfg = Debug|x64 + {F142A341-5EE0-442D-A15F-98AE9B48DBAE}.Debug|x64.Build.0 = Debug|x64 + {F142A341-5EE0-442D-A15F-98AE9B48DBAE}.Release|Win32.ActiveCfg = Release|Win32 + {F142A341-5EE0-442D-A15F-98AE9B48DBAE}.Release|Win32.Build.0 = Release|Win32 + {F142A341-5EE0-442D-A15F-98AE9B48DBAE}.Release|x64.ActiveCfg = Release|x64 + {F142A341-5EE0-442D-A15F-98AE9B48DBAE}.Release|x64.Build.0 = Release|x64 + {027FAC75-3FDB-4044-8DD0-BC297BD4C461}.Debug|Win32.ActiveCfg = Debug|Win32 + {027FAC75-3FDB-4044-8DD0-BC297BD4C461}.Debug|Win32.Build.0 = Debug|Win32 + {027FAC75-3FDB-4044-8DD0-BC297BD4C461}.Debug|x64.ActiveCfg = Debug|x64 + {027FAC75-3FDB-4044-8DD0-BC297BD4C461}.Debug|x64.Build.0 = Debug|x64 + {027FAC75-3FDB-4044-8DD0-BC297BD4C461}.Release|Win32.ActiveCfg = Release|Win32 + {027FAC75-3FDB-4044-8DD0-BC297BD4C461}.Release|Win32.Build.0 = Release|Win32 + {027FAC75-3FDB-4044-8DD0-BC297BD4C461}.Release|x64.ActiveCfg = Release|x64 + {027FAC75-3FDB-4044-8DD0-BC297BD4C461}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/galliumhook/minhook-multihook/build/VC15/libMinHook.vcxproj b/galliumhook/minhook-multihook/build/VC15/libMinHook.vcxproj new file mode 100644 index 0000000..829ac34 --- /dev/null +++ b/galliumhook/minhook-multihook/build/VC15/libMinHook.vcxproj @@ -0,0 +1,173 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {F142A341-5EE0-442D-A15F-98AE9B48DBAE} + libMinHook + Win32Proj + + + + StaticLibrary + Unicode + true + v141_xp + + + StaticLibrary + Unicode + v141_xp + + + StaticLibrary + Unicode + true + v141_xp + + + StaticLibrary + Unicode + v141_xp + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.40219.1 + $(SolutionDir)lib\$(Configuration)\ + $(Platform)\$(Configuration)\$(ProjectName)\ + $(SolutionDir)lib\$(Configuration)\ + $(Platform)\$(Configuration)\$(ProjectName)\ + $(SolutionDir)lib\$(Configuration)\ + $(Platform)\$(Configuration)\$(ProjectName)\ + $(SolutionDir)lib\$(Configuration)\ + $(Platform)\$(Configuration)\$(ProjectName)\ + $(ProjectName).x86 + $(ProjectName).x86 + $(ProjectName).x64 + $(ProjectName).x64 + + + + Disabled + %(AdditionalIncludeDirectories) + WIN32;_DEBUG;_LIB;STRICT;%(PreprocessorDefinitions) + false + EnableFastChecks + MultiThreadedDebug + Level3 + None + NoExtensions + + + + + + X64 + + + Disabled + %(AdditionalIncludeDirectories) + WIN32;_DEBUG;_LIB;STRICT;%(PreprocessorDefinitions) + false + EnableFastChecks + MultiThreadedDebug + Level3 + None + NotSet + + + + + + MinSpace + true + %(AdditionalIncludeDirectories) + WIN32;NDEBUG;_LIB;STRICT;%(PreprocessorDefinitions) + false + MultiThreaded + true + Level3 + None + AnySuitable + true + NoExtensions + + + + + + X64 + + + MinSpace + true + %(AdditionalIncludeDirectories) + WIN32;NDEBUG;_LIB;STRICT;%(PreprocessorDefinitions) + false + MultiThreaded + true + Level3 + None + true + AnySuitable + + + + + + + true + true + + + true + true + + + + + + + + + + + + + + + + + + diff --git a/galliumhook/minhook-multihook/build/VC15/libMinHook.vcxproj.filters b/galliumhook/minhook-multihook/build/VC15/libMinHook.vcxproj.filters new file mode 100644 index 0000000..f2d1d97 --- /dev/null +++ b/galliumhook/minhook-multihook/build/VC15/libMinHook.vcxproj.filters @@ -0,0 +1,55 @@ + + + + + Source Files + + + Source Files + + + Source Files + + + HDE + + + HDE + + + + + Header Files + + + Header Files + + + + HDE + + + HDE + + + HDE + + + HDE + + + HDE + + + + + {9d24b740-be2e-4cfd-b9a4-340a50946ee9} + + + {76381bc7-2863-4cc5-aede-926ec2c506e4} + + + {56ddb326-6179-430d-ae19-e13bfd767bfa} + + + \ No newline at end of file diff --git a/galliumhook/minhook-multihook/build/VC16/MinHook.vcxproj b/galliumhook/minhook-multihook/build/VC16/MinHook.vcxproj new file mode 100644 index 0000000..23ddafd --- /dev/null +++ b/galliumhook/minhook-multihook/build/VC16/MinHook.vcxproj @@ -0,0 +1,189 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {027FAC75-3FDB-4044-8DD0-BC297BD4C461} + MinHook + Win32Proj + + + + DynamicLibrary + Unicode + true + v142 + + + DynamicLibrary + Unicode + v142 + + + DynamicLibrary + Unicode + true + v142 + + + DynamicLibrary + Unicode + v142 + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.40219.1 + $(SolutionDir)bin\$(Configuration)\ + $(Platform)\$(Configuration)\$(ProjectName)\ + true + $(SolutionDir)bin\$(Configuration)\ + $(Platform)\$(Configuration)\$(ProjectName)\ + true + $(SolutionDir)bin\$(Configuration)\ + $(Platform)\$(Configuration)\$(ProjectName)\ + false + $(SolutionDir)bin\$(Configuration)\ + $(Platform)\$(Configuration)\$(ProjectName)\ + false + $(ProjectName).x86 + $(ProjectName).x86 + $(ProjectName).x64 + $(ProjectName).x64 + + + + Disabled + WIN32;_DEBUG;_WINDOWS;_USRDLL;MINHOOK_EXPORTS;%(PreprocessorDefinitions) + false + EnableFastChecks + MultiThreadedDebug + + + Level3 + None + + + $(SolutionDir)..\..\dll_resources\MinHook.def + false + Windows + MachineX86 + $(SolutionDir)lib\$(Configuration)\libMinHook.x86.lib;%(AdditionalDependencies) + + + + + X64 + + + Disabled + WIN32;_DEBUG;_WINDOWS;_USRDLL;MINHOOK_EXPORTS;%(PreprocessorDefinitions) + false + EnableFastChecks + MultiThreadedDebug + + + Level3 + None + + + $(SolutionDir)..\..\dll_resources\MinHook.def + false + Windows + MachineX64 + $(SolutionDir)lib\$(Configuration)\libMinHook.x64.lib;%(AdditionalDependencies) + + + + + MinSpace + true + WIN32;NDEBUG;_WINDOWS;_USRDLL;MINHOOK_EXPORTS;%(PreprocessorDefinitions) + MultiThreaded + true + + + Level3 + None + false + + + $(SolutionDir)..\..\dll_resources\MinHook.def + false + Windows + true + true + MachineX86 + $(SolutionDir)lib\$(Configuration)\libMinHook.x86.lib;%(AdditionalDependencies) + true + .CRT=.text + + + + + X64 + + + MinSpace + true + WIN32;NDEBUG;_WINDOWS;_USRDLL;MINHOOK_EXPORTS;%(PreprocessorDefinitions) + MultiThreaded + true + + + Level3 + None + false + + + $(SolutionDir)..\..\dll_resources\MinHook.def + false + Windows + true + true + MachineX64 + $(SolutionDir)lib\$(Configuration)\libMinHook.x64.lib;%(AdditionalDependencies) + true + .CRT=.text + + + + + + + + + + + + diff --git a/galliumhook/minhook-multihook/build/VC16/MinHookVC16.sln b/galliumhook/minhook-multihook/build/VC16/MinHookVC16.sln new file mode 100644 index 0000000..191b75c --- /dev/null +++ b/galliumhook/minhook-multihook/build/VC16/MinHookVC16.sln @@ -0,0 +1,41 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.28803.352 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libMinHook", "libMinHook.vcxproj", "{F142A341-5EE0-442D-A15F-98AE9B48DBAE}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MinHook", "MinHook.vcxproj", "{027FAC75-3FDB-4044-8DD0-BC297BD4C461}" + ProjectSection(ProjectDependencies) = postProject + {F142A341-5EE0-442D-A15F-98AE9B48DBAE} = {F142A341-5EE0-442D-A15F-98AE9B48DBAE} + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {F142A341-5EE0-442D-A15F-98AE9B48DBAE}.Debug|Win32.ActiveCfg = Debug|Win32 + {F142A341-5EE0-442D-A15F-98AE9B48DBAE}.Debug|Win32.Build.0 = Debug|Win32 + {F142A341-5EE0-442D-A15F-98AE9B48DBAE}.Debug|x64.ActiveCfg = Debug|x64 + {F142A341-5EE0-442D-A15F-98AE9B48DBAE}.Debug|x64.Build.0 = Debug|x64 + {F142A341-5EE0-442D-A15F-98AE9B48DBAE}.Release|Win32.ActiveCfg = Release|Win32 + {F142A341-5EE0-442D-A15F-98AE9B48DBAE}.Release|Win32.Build.0 = Release|Win32 + {F142A341-5EE0-442D-A15F-98AE9B48DBAE}.Release|x64.ActiveCfg = Release|x64 + {F142A341-5EE0-442D-A15F-98AE9B48DBAE}.Release|x64.Build.0 = Release|x64 + {027FAC75-3FDB-4044-8DD0-BC297BD4C461}.Debug|Win32.ActiveCfg = Debug|Win32 + {027FAC75-3FDB-4044-8DD0-BC297BD4C461}.Debug|Win32.Build.0 = Debug|Win32 + {027FAC75-3FDB-4044-8DD0-BC297BD4C461}.Debug|x64.ActiveCfg = Debug|x64 + {027FAC75-3FDB-4044-8DD0-BC297BD4C461}.Debug|x64.Build.0 = Debug|x64 + {027FAC75-3FDB-4044-8DD0-BC297BD4C461}.Release|Win32.ActiveCfg = Release|Win32 + {027FAC75-3FDB-4044-8DD0-BC297BD4C461}.Release|Win32.Build.0 = Release|Win32 + {027FAC75-3FDB-4044-8DD0-BC297BD4C461}.Release|x64.ActiveCfg = Release|x64 + {027FAC75-3FDB-4044-8DD0-BC297BD4C461}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/galliumhook/minhook-multihook/build/VC16/libMinHook.vcxproj b/galliumhook/minhook-multihook/build/VC16/libMinHook.vcxproj new file mode 100644 index 0000000..6e2c930 --- /dev/null +++ b/galliumhook/minhook-multihook/build/VC16/libMinHook.vcxproj @@ -0,0 +1,174 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {F142A341-5EE0-442D-A15F-98AE9B48DBAE} + libMinHook + Win32Proj + 10.0 + + + + StaticLibrary + Unicode + true + v142 + + + StaticLibrary + Unicode + v142 + + + StaticLibrary + Unicode + true + v143 + + + StaticLibrary + Unicode + v143 + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.40219.1 + $(SolutionDir)lib\$(Configuration)\ + $(Platform)\$(Configuration)\$(ProjectName)\ + $(SolutionDir)lib\$(Configuration)\ + $(Platform)\$(Configuration)\$(ProjectName)\ + $(SolutionDir)lib\$(Configuration)\ + $(Platform)\$(Configuration)\$(ProjectName)\ + $(SolutionDir)lib\$(Configuration)\ + $(Platform)\$(Configuration)\$(ProjectName)\ + $(ProjectName).x86 + $(ProjectName).x86 + $(ProjectName).x64 + $(ProjectName).x64 + + + + Disabled + %(AdditionalIncludeDirectories) + WIN32;_DEBUG;_LIB;STRICT;%(PreprocessorDefinitions) + false + EnableFastChecks + MultiThreadedDebug + Level3 + None + NoExtensions + + + + + + X64 + + + Disabled + %(AdditionalIncludeDirectories) + WIN32;_DEBUG;_LIB;STRICT;%(PreprocessorDefinitions) + false + EnableFastChecks + MultiThreadedDebug + Level3 + None + NotSet + + + + + + MinSpace + true + %(AdditionalIncludeDirectories) + WIN32;NDEBUG;_LIB;STRICT;%(PreprocessorDefinitions) + false + MultiThreaded + true + Level3 + None + AnySuitable + true + NoExtensions + + + + + + X64 + + + MinSpace + true + %(AdditionalIncludeDirectories) + WIN32;NDEBUG;_LIB;STRICT;%(PreprocessorDefinitions) + false + MultiThreaded + true + Level3 + None + true + AnySuitable + + + + + + + true + true + + + true + true + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/galliumhook/minhook-multihook/build/VC16/libMinHook.vcxproj.filters b/galliumhook/minhook-multihook/build/VC16/libMinHook.vcxproj.filters new file mode 100644 index 0000000..f2d1d97 --- /dev/null +++ b/galliumhook/minhook-multihook/build/VC16/libMinHook.vcxproj.filters @@ -0,0 +1,55 @@ + + + + + Source Files + + + Source Files + + + Source Files + + + HDE + + + HDE + + + + + Header Files + + + Header Files + + + + HDE + + + HDE + + + HDE + + + HDE + + + HDE + + + + + {9d24b740-be2e-4cfd-b9a4-340a50946ee9} + + + {76381bc7-2863-4cc5-aede-926ec2c506e4} + + + {56ddb326-6179-430d-ae19-e13bfd767bfa} + + + \ No newline at end of file diff --git a/galliumhook/minhook-multihook/build/VC9/MinHook.vcproj b/galliumhook/minhook-multihook/build/VC9/MinHook.vcproj new file mode 100644 index 0000000..4bad257 --- /dev/null +++ b/galliumhook/minhook-multihook/build/VC9/MinHook.vcproj @@ -0,0 +1,343 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/galliumhook/minhook-multihook/build/VC9/MinHookVC9.sln b/galliumhook/minhook-multihook/build/VC9/MinHookVC9.sln new file mode 100644 index 0000000..869f5b6 --- /dev/null +++ b/galliumhook/minhook-multihook/build/VC9/MinHookVC9.sln @@ -0,0 +1,39 @@ + +Microsoft Visual Studio Solution File, Format Version 10.00 +# Visual Studio 2008 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libMinHook", "libMinHook.vcproj", "{F142A341-5EE0-442D-A15F-98AE9B48DBAE}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MinHook", "MinHook.vcproj", "{027FAC75-3FDB-4044-8DD0-BC297BD4C461}" + ProjectSection(ProjectDependencies) = postProject + {F142A341-5EE0-442D-A15F-98AE9B48DBAE} = {F142A341-5EE0-442D-A15F-98AE9B48DBAE} + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {F142A341-5EE0-442D-A15F-98AE9B48DBAE}.Debug|Win32.ActiveCfg = Debug|Win32 + {F142A341-5EE0-442D-A15F-98AE9B48DBAE}.Debug|Win32.Build.0 = Debug|Win32 + {F142A341-5EE0-442D-A15F-98AE9B48DBAE}.Debug|x64.ActiveCfg = Debug|x64 + {F142A341-5EE0-442D-A15F-98AE9B48DBAE}.Debug|x64.Build.0 = Debug|x64 + {F142A341-5EE0-442D-A15F-98AE9B48DBAE}.Release|Win32.ActiveCfg = Release|Win32 + {F142A341-5EE0-442D-A15F-98AE9B48DBAE}.Release|Win32.Build.0 = Release|Win32 + {F142A341-5EE0-442D-A15F-98AE9B48DBAE}.Release|x64.ActiveCfg = Release|x64 + {F142A341-5EE0-442D-A15F-98AE9B48DBAE}.Release|x64.Build.0 = Release|x64 + {027FAC75-3FDB-4044-8DD0-BC297BD4C461}.Debug|Win32.ActiveCfg = Debug|Win32 + {027FAC75-3FDB-4044-8DD0-BC297BD4C461}.Debug|Win32.Build.0 = Debug|Win32 + {027FAC75-3FDB-4044-8DD0-BC297BD4C461}.Debug|x64.ActiveCfg = Debug|x64 + {027FAC75-3FDB-4044-8DD0-BC297BD4C461}.Debug|x64.Build.0 = Debug|x64 + {027FAC75-3FDB-4044-8DD0-BC297BD4C461}.Release|Win32.ActiveCfg = Release|Win32 + {027FAC75-3FDB-4044-8DD0-BC297BD4C461}.Release|Win32.Build.0 = Release|Win32 + {027FAC75-3FDB-4044-8DD0-BC297BD4C461}.Release|x64.ActiveCfg = Release|x64 + {027FAC75-3FDB-4044-8DD0-BC297BD4C461}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/galliumhook/minhook-multihook/build/VC9/libMinHook.vcproj b/galliumhook/minhook-multihook/build/VC9/libMinHook.vcproj new file mode 100644 index 0000000..68b0c05 --- /dev/null +++ b/galliumhook/minhook-multihook/build/VC9/libMinHook.vcproj @@ -0,0 +1,410 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/galliumhook/minhook-multihook/cmake/minhook-config.cmake.in b/galliumhook/minhook-multihook/cmake/minhook-config.cmake.in new file mode 100644 index 0000000..14e6463 --- /dev/null +++ b/galliumhook/minhook-multihook/cmake/minhook-config.cmake.in @@ -0,0 +1,39 @@ +# MinHook - The Minimalistic API Hooking Library for x64/x86 +# Copyright (C) 2009-2017 Tsuda Kageyu. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER +# OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +set(MINHOOK_MAJOR_VERSION "@MINHOOK_MAJOR_VERSION@") +set(MINHOOK_MINOR_VERSION "@MINHOOK_MINOR_VERSION@") +set(MINHOOK_PATCH_VERSION "@MINHOOK_PATCH_VERSION@") +set(MINHOOK_VERSION "@MINHOOK_VERSION@") + +@PACKAGE_INIT@ + +set(MINHOOK_FOUND ON) + +set_and_check(MINHOOK_INCLUDE_DIRS "${PACKAGE_PREFIX_DIR}/include/") +set_and_check(MINHOOK_LIBRARY_DIRS "${PACKAGE_PREFIX_DIR}/lib") + +include("${PACKAGE_PREFIX_DIR}/lib/minhook/minhook-targets.cmake") diff --git a/galliumhook/minhook-multihook/dll_resources/MinHook.def b/galliumhook/minhook-multihook/dll_resources/MinHook.def new file mode 100644 index 0000000..77bd92f --- /dev/null +++ b/galliumhook/minhook-multihook/dll_resources/MinHook.def @@ -0,0 +1,21 @@ +EXPORTS + MH_Initialize + MH_Uninitialize + MH_SetThreadFreezeMethod + + MH_CreateHook + MH_CreateHookEx + MH_CreateHookApi + MH_CreateHookApiEx + MH_RemoveHook + MH_RemoveHookEx + MH_EnableHook + MH_EnableHookEx + MH_DisableHook + MH_DisableHookEx + MH_QueueEnableHook + MH_QueueEnableHookEx + MH_QueueDisableHook + MH_QueueDisableHookEx + MH_ApplyQueued + MH_StatusToString diff --git a/galliumhook/minhook-multihook/dll_resources/MinHook.rc b/galliumhook/minhook-multihook/dll_resources/MinHook.rc new file mode 100644 index 0000000..7cbacb7 --- /dev/null +++ b/galliumhook/minhook-multihook/dll_resources/MinHook.rc @@ -0,0 +1,32 @@ +1 VERSIONINFO + FILEVERSION 1,3,3,0 + PRODUCTVERSION 1,3,3,0 + FILEFLAGSMASK 0x17L +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "CompanyName", "Tsuda Kageyu" + VALUE "FileDescription", "MinHook - The Minimalistic API Hook Library for x64/x86" + VALUE "FileVersion", "1.3.3.0" + VALUE "InternalName", "MinHookD" + VALUE "LegalCopyright", "Copyright (C) 2009-2017 Tsuda Kageyu. All rights reserved." + VALUE "LegalTrademarks", "Tsuda Kageyu" + VALUE "ProductName", "MinHook DLL" + VALUE "ProductVersion", "1.3.3.0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END diff --git a/galliumhook/minhook-multihook/include/MinHook.h b/galliumhook/minhook-multihook/include/MinHook.h new file mode 100644 index 0000000..1b9e088 --- /dev/null +++ b/galliumhook/minhook-multihook/include/MinHook.h @@ -0,0 +1,238 @@ +/* + * MinHook - The Minimalistic API Hooking Library for x64/x86 + * Copyright (C) 2009-2017 Tsuda Kageyu. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#if !(defined _M_IX86) && !(defined _M_X64) && !(defined __i386__) && !(defined __x86_64__) + #error MinHook supports only x86 and x64 systems. +#endif + +#include + +// MinHook Error Codes. +typedef enum MH_STATUS +{ + // Unknown error. Should not be returned. + MH_UNKNOWN = -1, + + // Successful. + MH_OK = 0, + + // MinHook is already initialized. + MH_ERROR_ALREADY_INITIALIZED, + + // MinHook is not initialized yet, or already uninitialized. + MH_ERROR_NOT_INITIALIZED, + + // The hook for the specified target function is already created. + MH_ERROR_ALREADY_CREATED, + + // The hook for the specified target function is not created yet. + MH_ERROR_NOT_CREATED, + + // The hook for the specified target function is already enabled. + MH_ERROR_ENABLED, + + // The hook for the specified target function is not enabled yet, or already + // disabled. + MH_ERROR_DISABLED, + + // The specified pointer is invalid. It points the address of non-allocated + // and/or non-executable region. + MH_ERROR_NOT_EXECUTABLE, + + // The specified target function cannot be hooked. + MH_ERROR_UNSUPPORTED_FUNCTION, + + // Failed to allocate memory. + MH_ERROR_MEMORY_ALLOC, + + // Failed to change the memory protection. + MH_ERROR_MEMORY_PROTECT, + + // The specified module is not loaded. + MH_ERROR_MODULE_NOT_FOUND, + + // The specified function is not found. + MH_ERROR_FUNCTION_NOT_FOUND, + + // Failed to create, or to wait for the main mutex. + MH_ERROR_MUTEX_FAILURE +} MH_STATUS; + +// The method of suspending and resuming threads. +// +// It's possible to add an additional method using PssCaptureSnapshot. +// Pros: Documented, fast. +// Cons: Available from Windows 8.1, less reliable. +typedef enum MH_THREAD_FREEZE_METHOD +{ + // The original MinHook method, using CreateToolhelp32Snapshot. Documented + // and supported on all Windows versions, but very slow and less reliable. + MH_FREEZE_METHOD_ORIGINAL = 0, + + // A much faster and more reliable, but undocumented method, using + // NtGetNextThread. Supported since Windows Vista, on older versions falls + // back to MH_ORIGINAL. + MH_FREEZE_METHOD_FAST_UNDOCUMENTED, + + // Threads are not suspended and instruction pointer registers are not + // adjusted. Don't use this method unless you understand the implications + // and know that it's safe. + MH_FREEZE_METHOD_NONE_UNSAFE +} MH_THREAD_FREEZE_METHOD; + +// Can be passed as a parameter to MH_EnableHook, MH_DisableHook, +// MH_QueueEnableHook or MH_QueueDisableHook. +#define MH_ALL_HOOKS NULL + +#ifdef __cplusplus +extern "C" { +#endif + + // Initialize the MinHook library. You must call this function EXACTLY ONCE + // at the beginning of your program. + MH_STATUS WINAPI MH_Initialize(VOID); + + // Uninitialize the MinHook library. You must call this function EXACTLY + // ONCE at the end of your program. + MH_STATUS WINAPI MH_Uninitialize(VOID); + + // Set the method of suspending and resuming threads. + MH_STATUS WINAPI MH_SetThreadFreezeMethod(MH_THREAD_FREEZE_METHOD method); + + // Creates a hook for the specified target function, in disabled state. + // Parameters: + // hookIdent [in] A hook identifier, can be set to different values for + // different hooks to hook the same function more than + // once. Default value: 0. + // pTarget [in] A pointer to the target function, which will be + // overridden by the detour function. + // pDetour [in] A pointer to the detour function, which will override + // the target function. + // ppOriginal [out] A pointer to the trampoline function, which will be + // used to call the original target function. + // This parameter can be NULL. + MH_STATUS WINAPI MH_CreateHook(LPVOID pTarget, LPVOID pDetour, LPVOID *ppOriginal); + MH_STATUS WINAPI MH_CreateHookEx(ULONG_PTR hookIdent, LPVOID pTarget, LPVOID pDetour, LPVOID *ppOriginal); + + // Creates a hook for the specified API function, in disabled state. + // Parameters: + // pszModule [in] A pointer to the loaded module name which contains the + // target function. + // pszProcName [in] A pointer to the target function name, which will be + // overridden by the detour function. + // pDetour [in] A pointer to the detour function, which will override + // the target function. + // ppOriginal [out] A pointer to the trampoline function, which will be + // used to call the original target function. + // This parameter can be NULL. + MH_STATUS WINAPI MH_CreateHookApi( + LPCWSTR pszModule, LPCSTR pszProcName, LPVOID pDetour, LPVOID *ppOriginal); + + // Creates a hook for the specified API function, in disabled state. + // Parameters: + // pszModule [in] A pointer to the loaded module name which contains the + // target function. + // pszProcName [in] A pointer to the target function name, which will be + // overridden by the detour function. + // pDetour [in] A pointer to the detour function, which will override + // the target function. + // ppOriginal [out] A pointer to the trampoline function, which will be + // used to call the original target function. + // This parameter can be NULL. + // ppTarget [out] A pointer to the target function, which will be used + // with other functions. + // This parameter can be NULL. + MH_STATUS WINAPI MH_CreateHookApiEx( + LPCWSTR pszModule, LPCSTR pszProcName, LPVOID pDetour, LPVOID *ppOriginal, LPVOID *ppTarget); + + // Removes an already created hook. + // Parameters: + // hookIdent [in] A hook identifier, can be set to different values for + // different hooks to hook the same function more than + // once. Default value: 0. + // pTarget [in] A pointer to the target function. + // If this parameter is MH_ALL_HOOKS, all created hooks are + // removed in one go. + MH_STATUS WINAPI MH_RemoveHook(LPVOID pTarget); + MH_STATUS WINAPI MH_RemoveHookEx(ULONG_PTR hookIdent, LPVOID pTarget); + + // Enables an already created hook. + // Parameters: + // hookIdent [in] A hook identifier, can be set to different values for + // different hooks to hook the same function more than + // once. Default value: 0. + // pTarget [in] A pointer to the target function. + // If this parameter is MH_ALL_HOOKS, all created hooks are + // enabled in one go. + MH_STATUS WINAPI MH_EnableHook(LPVOID pTarget); + MH_STATUS WINAPI MH_EnableHookEx(ULONG_PTR hookIdent, LPVOID pTarget); + + // Disables an already created hook. + // Parameters: + // hookIdent [in] A hook identifier, can be set to different values for + // different hooks to hook the same function more than + // once. Default value: 0. + // pTarget [in] A pointer to the target function. + // If this parameter is MH_ALL_HOOKS, all created hooks are + // disabled in one go. + MH_STATUS WINAPI MH_DisableHook(LPVOID pTarget); + MH_STATUS WINAPI MH_DisableHookEx(ULONG_PTR hookIdent, LPVOID pTarget); + + // Queues to enable an already created hook. + // Parameters: + // hookIdent [in] A hook identifier, can be set to different values for + // different hooks to hook the same function more than + // once. Default value: 0. + // pTarget [in] A pointer to the target function. + // If this parameter is MH_ALL_HOOKS, all created hooks are + // queued to be enabled. + MH_STATUS WINAPI MH_QueueEnableHook(LPVOID pTarget); + MH_STATUS WINAPI MH_QueueEnableHookEx(ULONG_PTR hookIdent, LPVOID pTarget); + + // Queues to disable an already created hook. + // Parameters: + // hookIdent [in] A hook identifier, can be set to different values for + // different hooks to hook the same function more than + // once. Default value: 0. + // pTarget [in] A pointer to the target function. + // If this parameter is MH_ALL_HOOKS, all created hooks are + // queued to be disabled. + MH_STATUS WINAPI MH_QueueDisableHook(LPVOID pTarget); + MH_STATUS WINAPI MH_QueueDisableHookEx(ULONG_PTR hookIdent, LPVOID pTarget); + + // Applies all queued changes in one go. + MH_STATUS WINAPI MH_ApplyQueued(VOID); + + // Translates the MH_STATUS to its name as a string. + const char * WINAPI MH_StatusToString(MH_STATUS status); + +#ifdef __cplusplus +} +#endif diff --git a/galliumhook/minhook-multihook/src/buffer.c b/galliumhook/minhook-multihook/src/buffer.c new file mode 100644 index 0000000..55412b0 --- /dev/null +++ b/galliumhook/minhook-multihook/src/buffer.c @@ -0,0 +1,312 @@ +/* + * MinHook - The Minimalistic API Hooking Library for x64/x86 + * Copyright (C) 2009-2017 Tsuda Kageyu. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include "buffer.h" + +// Size of each memory block. (= page size of VirtualAlloc) +#define MEMORY_BLOCK_SIZE 0x1000 + +// Max range for seeking a memory block. (= 1024MB) +#define MAX_MEMORY_RANGE 0x40000000 + +// Memory protection flags to check the executable address. +#define PAGE_EXECUTE_FLAGS \ + (PAGE_EXECUTE | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY) + +// Memory slot. +typedef struct _MEMORY_SLOT +{ + union + { + struct _MEMORY_SLOT *pNext; + UINT8 buffer[MEMORY_SLOT_SIZE]; + }; +} MEMORY_SLOT, *PMEMORY_SLOT; + +// Memory block info. Placed at the head of each block. +typedef struct _MEMORY_BLOCK +{ + struct _MEMORY_BLOCK *pNext; + PMEMORY_SLOT pFree; // First element of the free slot list. + UINT usedCount; +} MEMORY_BLOCK, *PMEMORY_BLOCK; + +//------------------------------------------------------------------------- +// Global Variables: +//------------------------------------------------------------------------- + +// First element of the memory block list. +PMEMORY_BLOCK g_pMemoryBlocks; + +//------------------------------------------------------------------------- +VOID InitializeBuffer(VOID) +{ + // Nothing to do for now. +} + +//------------------------------------------------------------------------- +VOID UninitializeBuffer(VOID) +{ + PMEMORY_BLOCK pBlock = g_pMemoryBlocks; + g_pMemoryBlocks = NULL; + + while (pBlock) + { + PMEMORY_BLOCK pNext = pBlock->pNext; + VirtualFree(pBlock, 0, MEM_RELEASE); + pBlock = pNext; + } +} + +//------------------------------------------------------------------------- +#if defined(_M_X64) || defined(__x86_64__) +static LPVOID FindPrevFreeRegion(LPVOID pAddress, LPVOID pMinAddr, DWORD dwAllocationGranularity) +{ + ULONG_PTR tryAddr = (ULONG_PTR)pAddress; + + // Round down to the allocation granularity. + tryAddr -= tryAddr % dwAllocationGranularity; + + // Start from the previous allocation granularity multiply. + tryAddr -= dwAllocationGranularity; + + while (tryAddr >= (ULONG_PTR)pMinAddr) + { + MEMORY_BASIC_INFORMATION mbi; + if (VirtualQuery((LPVOID)tryAddr, &mbi, sizeof(mbi)) == 0) + break; + + if (mbi.State == MEM_FREE) + return (LPVOID)tryAddr; + + if ((ULONG_PTR)mbi.AllocationBase < dwAllocationGranularity) + break; + + tryAddr = (ULONG_PTR)mbi.AllocationBase - dwAllocationGranularity; + } + + return NULL; +} +#endif + +//------------------------------------------------------------------------- +#if defined(_M_X64) || defined(__x86_64__) +static LPVOID FindNextFreeRegion(LPVOID pAddress, LPVOID pMaxAddr, DWORD dwAllocationGranularity) +{ + ULONG_PTR tryAddr = (ULONG_PTR)pAddress; + + // Round down to the allocation granularity. + tryAddr -= tryAddr % dwAllocationGranularity; + + // Start from the next allocation granularity multiply. + tryAddr += dwAllocationGranularity; + + while (tryAddr <= (ULONG_PTR)pMaxAddr) + { + MEMORY_BASIC_INFORMATION mbi; + if (VirtualQuery((LPVOID)tryAddr, &mbi, sizeof(mbi)) == 0) + break; + + if (mbi.State == MEM_FREE) + return (LPVOID)tryAddr; + + tryAddr = (ULONG_PTR)mbi.BaseAddress + mbi.RegionSize; + + // Round up to the next allocation granularity. + tryAddr += dwAllocationGranularity - 1; + tryAddr -= tryAddr % dwAllocationGranularity; + } + + return NULL; +} +#endif + +//------------------------------------------------------------------------- +static PMEMORY_BLOCK GetMemoryBlock(LPVOID pOrigin) +{ + PMEMORY_BLOCK pBlock; +#if defined(_M_X64) || defined(__x86_64__) + ULONG_PTR minAddr; + ULONG_PTR maxAddr; + + SYSTEM_INFO si; + GetSystemInfo(&si); + minAddr = (ULONG_PTR)si.lpMinimumApplicationAddress; + maxAddr = (ULONG_PTR)si.lpMaximumApplicationAddress; + + // pOrigin ± 512MB + if ((ULONG_PTR)pOrigin > MAX_MEMORY_RANGE && minAddr < (ULONG_PTR)pOrigin - MAX_MEMORY_RANGE) + minAddr = (ULONG_PTR)pOrigin - MAX_MEMORY_RANGE; + + if (maxAddr > (ULONG_PTR)pOrigin + MAX_MEMORY_RANGE) + maxAddr = (ULONG_PTR)pOrigin + MAX_MEMORY_RANGE; + + // Make room for MEMORY_BLOCK_SIZE bytes. + maxAddr -= MEMORY_BLOCK_SIZE - 1; +#endif + + // Look the registered blocks for a reachable one. + for (pBlock = g_pMemoryBlocks; pBlock != NULL; pBlock = pBlock->pNext) + { +#if defined(_M_X64) || defined(__x86_64__) + // Ignore the blocks too far. + if ((ULONG_PTR)pBlock < minAddr || (ULONG_PTR)pBlock >= maxAddr) + continue; +#endif + // The block has at least one unused slot. + if (pBlock->pFree != NULL) + return pBlock; + } + +#if defined(_M_X64) || defined(__x86_64__) + // Alloc a new block above if not found. + { + LPVOID pAlloc = pOrigin; + while ((ULONG_PTR)pAlloc >= minAddr) + { + pAlloc = FindPrevFreeRegion(pAlloc, (LPVOID)minAddr, si.dwAllocationGranularity); + if (pAlloc == NULL) + break; + + pBlock = (PMEMORY_BLOCK)VirtualAlloc( + pAlloc, MEMORY_BLOCK_SIZE, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); + if (pBlock != NULL) + break; + } + } + + // Alloc a new block below if not found. + if (pBlock == NULL) + { + LPVOID pAlloc = pOrigin; + while ((ULONG_PTR)pAlloc <= maxAddr) + { + pAlloc = FindNextFreeRegion(pAlloc, (LPVOID)maxAddr, si.dwAllocationGranularity); + if (pAlloc == NULL) + break; + + pBlock = (PMEMORY_BLOCK)VirtualAlloc( + pAlloc, MEMORY_BLOCK_SIZE, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); + if (pBlock != NULL) + break; + } + } +#else + // In x86 mode, a memory block can be placed anywhere. + pBlock = (PMEMORY_BLOCK)VirtualAlloc( + NULL, MEMORY_BLOCK_SIZE, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); +#endif + + if (pBlock != NULL) + { + // Build a linked list of all the slots. + PMEMORY_SLOT pSlot = (PMEMORY_SLOT)pBlock + 1; + pBlock->pFree = NULL; + pBlock->usedCount = 0; + do + { + pSlot->pNext = pBlock->pFree; + pBlock->pFree = pSlot; + pSlot++; + } while ((ULONG_PTR)pSlot - (ULONG_PTR)pBlock <= MEMORY_BLOCK_SIZE - MEMORY_SLOT_SIZE); + + pBlock->pNext = g_pMemoryBlocks; + g_pMemoryBlocks = pBlock; + } + + return pBlock; +} + +//------------------------------------------------------------------------- +LPVOID AllocateBuffer(LPVOID pOrigin) +{ + PMEMORY_SLOT pSlot; + PMEMORY_BLOCK pBlock = GetMemoryBlock(pOrigin); + if (pBlock == NULL) + return NULL; + + // Remove an unused slot from the list. + pSlot = pBlock->pFree; + pBlock->pFree = pSlot->pNext; + pBlock->usedCount++; +#ifdef _DEBUG + // Fill the slot with INT3 for debugging. + memset(pSlot, 0xCC, sizeof(MEMORY_SLOT)); +#endif + return pSlot; +} + +//------------------------------------------------------------------------- +VOID FreeBuffer(LPVOID pBuffer) +{ + PMEMORY_BLOCK pBlock = g_pMemoryBlocks; + PMEMORY_BLOCK pPrev = NULL; + ULONG_PTR pTargetBlock = ((ULONG_PTR)pBuffer / MEMORY_BLOCK_SIZE) * MEMORY_BLOCK_SIZE; + + while (pBlock != NULL) + { + if ((ULONG_PTR)pBlock == pTargetBlock) + { + PMEMORY_SLOT pSlot = (PMEMORY_SLOT)pBuffer; +#ifdef _DEBUG + // Clear the released slot for debugging. + memset(pSlot, 0x00, sizeof(MEMORY_SLOT)); +#endif + // Restore the released slot to the list. + pSlot->pNext = pBlock->pFree; + pBlock->pFree = pSlot; + pBlock->usedCount--; + + // Free if unused. + if (pBlock->usedCount == 0) + { + if (pPrev) + pPrev->pNext = pBlock->pNext; + else + g_pMemoryBlocks = pBlock->pNext; + + VirtualFree(pBlock, 0, MEM_RELEASE); + } + + break; + } + + pPrev = pBlock; + pBlock = pBlock->pNext; + } +} + +//------------------------------------------------------------------------- +BOOL IsExecutableAddress(LPVOID pAddress) +{ + MEMORY_BASIC_INFORMATION mi; + VirtualQuery(pAddress, &mi, sizeof(mi)); + + return (mi.State == MEM_COMMIT && (mi.Protect & PAGE_EXECUTE_FLAGS)); +} diff --git a/galliumhook/minhook-multihook/src/buffer.h b/galliumhook/minhook-multihook/src/buffer.h new file mode 100644 index 0000000..4b5915f --- /dev/null +++ b/galliumhook/minhook-multihook/src/buffer.h @@ -0,0 +1,42 @@ +/* + * MinHook - The Minimalistic API Hooking Library for x64/x86 + * Copyright (C) 2009-2017 Tsuda Kageyu. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +// Size of each memory slot. +#if defined(_M_X64) || defined(__x86_64__) + #define MEMORY_SLOT_SIZE 64 +#else + #define MEMORY_SLOT_SIZE 64 +#endif + +VOID InitializeBuffer(VOID); +VOID UninitializeBuffer(VOID); +LPVOID AllocateBuffer(LPVOID pOrigin); +VOID FreeBuffer(LPVOID pBuffer); +BOOL IsExecutableAddress(LPVOID pAddress); diff --git a/galliumhook/minhook-multihook/src/hde/hde32.c b/galliumhook/minhook-multihook/src/hde/hde32.c new file mode 100644 index 0000000..eb6af9b --- /dev/null +++ b/galliumhook/minhook-multihook/src/hde/hde32.c @@ -0,0 +1,324 @@ +/* + * Hacker Disassembler Engine 32 C + * Copyright (c) 2008-2009, Vyacheslav Patkov. + * All rights reserved. + * + */ + +#if defined(_M_IX86) || defined(__i386__) + +#include +#include "hde32.h" +#include "table32.h" + +unsigned int hde32_disasm(const void *code, hde32s *hs) +{ + uint8_t x, c, *p = (uint8_t *)code, cflags, opcode, pref = 0; + uint8_t *ht = hde32_table, m_mod, m_reg, m_rm, disp_size = 0; + + memset(hs, 0, sizeof(hde32s)); + + for (x = 16; x; x--) + switch (c = *p++) { + case 0xf3: + hs->p_rep = c; + pref |= PRE_F3; + break; + case 0xf2: + hs->p_rep = c; + pref |= PRE_F2; + break; + case 0xf0: + hs->p_lock = c; + pref |= PRE_LOCK; + break; + case 0x26: case 0x2e: case 0x36: + case 0x3e: case 0x64: case 0x65: + hs->p_seg = c; + pref |= PRE_SEG; + break; + case 0x66: + hs->p_66 = c; + pref |= PRE_66; + break; + case 0x67: + hs->p_67 = c; + pref |= PRE_67; + break; + default: + goto pref_done; + } + pref_done: + + hs->flags = (uint32_t)pref << 23; + + if (!pref) + pref |= PRE_NONE; + + if ((hs->opcode = c) == 0x0f) { + hs->opcode2 = c = *p++; + ht += DELTA_OPCODES; + } else if (c >= 0xa0 && c <= 0xa3) { + if (pref & PRE_67) + pref |= PRE_66; + else + pref &= ~PRE_66; + } + + opcode = c; + cflags = ht[ht[opcode / 4] + (opcode % 4)]; + + if (cflags == C_ERROR) { + hs->flags |= F_ERROR | F_ERROR_OPCODE; + cflags = 0; + if ((opcode & -3) == 0x24) + cflags++; + } + + x = 0; + if (cflags & C_GROUP) { + uint16_t t; + t = *(uint16_t *)(ht + (cflags & 0x7f)); + cflags = (uint8_t)t; + x = (uint8_t)(t >> 8); + } + + if (hs->opcode2) { + ht = hde32_table + DELTA_PREFIXES; + if (ht[ht[opcode / 4] + (opcode % 4)] & pref) + hs->flags |= F_ERROR | F_ERROR_OPCODE; + } + + if (cflags & C_MODRM) { + hs->flags |= F_MODRM; + hs->modrm = c = *p++; + hs->modrm_mod = m_mod = c >> 6; + hs->modrm_rm = m_rm = c & 7; + hs->modrm_reg = m_reg = (c & 0x3f) >> 3; + + if (x && ((x << m_reg) & 0x80)) + hs->flags |= F_ERROR | F_ERROR_OPCODE; + + if (!hs->opcode2 && opcode >= 0xd9 && opcode <= 0xdf) { + uint8_t t = opcode - 0xd9; + if (m_mod == 3) { + ht = hde32_table + DELTA_FPU_MODRM + t*8; + t = ht[m_reg] << m_rm; + } else { + ht = hde32_table + DELTA_FPU_REG; + t = ht[t] << m_reg; + } + if (t & 0x80) + hs->flags |= F_ERROR | F_ERROR_OPCODE; + } + + if (pref & PRE_LOCK) { + if (m_mod == 3) { + hs->flags |= F_ERROR | F_ERROR_LOCK; + } else { + uint8_t *table_end, op = opcode; + if (hs->opcode2) { + ht = hde32_table + DELTA_OP2_LOCK_OK; + table_end = ht + DELTA_OP_ONLY_MEM - DELTA_OP2_LOCK_OK; + } else { + ht = hde32_table + DELTA_OP_LOCK_OK; + table_end = ht + DELTA_OP2_LOCK_OK - DELTA_OP_LOCK_OK; + op &= -2; + } + for (; ht != table_end; ht++) + if (*ht++ == op) { + if (!((*ht << m_reg) & 0x80)) + goto no_lock_error; + else + break; + } + hs->flags |= F_ERROR | F_ERROR_LOCK; + no_lock_error: + ; + } + } + + if (hs->opcode2) { + switch (opcode) { + case 0x20: case 0x22: + m_mod = 3; + if (m_reg > 4 || m_reg == 1) + goto error_operand; + else + goto no_error_operand; + case 0x21: case 0x23: + m_mod = 3; + if (m_reg == 4 || m_reg == 5) + goto error_operand; + else + goto no_error_operand; + } + } else { + switch (opcode) { + case 0x8c: + if (m_reg > 5) + goto error_operand; + else + goto no_error_operand; + case 0x8e: + if (m_reg == 1 || m_reg > 5) + goto error_operand; + else + goto no_error_operand; + } + } + + if (m_mod == 3) { + uint8_t *table_end; + if (hs->opcode2) { + ht = hde32_table + DELTA_OP2_ONLY_MEM; + table_end = ht + sizeof(hde32_table) - DELTA_OP2_ONLY_MEM; + } else { + ht = hde32_table + DELTA_OP_ONLY_MEM; + table_end = ht + DELTA_OP2_ONLY_MEM - DELTA_OP_ONLY_MEM; + } + for (; ht != table_end; ht += 2) + if (*ht++ == opcode) { + if ((*ht++ & pref) && !((*ht << m_reg) & 0x80)) + goto error_operand; + else + break; + } + goto no_error_operand; + } else if (hs->opcode2) { + switch (opcode) { + case 0x50: case 0xd7: case 0xf7: + if (pref & (PRE_NONE | PRE_66)) + goto error_operand; + break; + case 0xd6: + if (pref & (PRE_F2 | PRE_F3)) + goto error_operand; + break; + case 0xc5: + goto error_operand; + } + goto no_error_operand; + } else + goto no_error_operand; + + error_operand: + hs->flags |= F_ERROR | F_ERROR_OPERAND; + no_error_operand: + + c = *p++; + if (m_reg <= 1) { + if (opcode == 0xf6) + cflags |= C_IMM8; + else if (opcode == 0xf7) + cflags |= C_IMM_P66; + } + + switch (m_mod) { + case 0: + if (pref & PRE_67) { + if (m_rm == 6) + disp_size = 2; + } else + if (m_rm == 5) + disp_size = 4; + break; + case 1: + disp_size = 1; + break; + case 2: + disp_size = 2; + if (!(pref & PRE_67)) + disp_size <<= 1; + break; + } + + if (m_mod != 3 && m_rm == 4 && !(pref & PRE_67)) { + hs->flags |= F_SIB; + p++; + hs->sib = c; + hs->sib_scale = c >> 6; + hs->sib_index = (c & 0x3f) >> 3; + if ((hs->sib_base = c & 7) == 5 && !(m_mod & 1)) + disp_size = 4; + } + + p--; + switch (disp_size) { + case 1: + hs->flags |= F_DISP8; + hs->disp.disp8 = *p; + break; + case 2: + hs->flags |= F_DISP16; + hs->disp.disp16 = *(uint16_t *)p; + break; + case 4: + hs->flags |= F_DISP32; + hs->disp.disp32 = *(uint32_t *)p; + break; + } + p += disp_size; + } else if (pref & PRE_LOCK) + hs->flags |= F_ERROR | F_ERROR_LOCK; + + if (cflags & C_IMM_P66) { + if (cflags & C_REL32) { + if (pref & PRE_66) { + hs->flags |= F_IMM16 | F_RELATIVE; + hs->imm.imm16 = *(uint16_t *)p; + p += 2; + goto disasm_done; + } + goto rel32_ok; + } + if (pref & PRE_66) { + hs->flags |= F_IMM16; + hs->imm.imm16 = *(uint16_t *)p; + p += 2; + } else { + hs->flags |= F_IMM32; + hs->imm.imm32 = *(uint32_t *)p; + p += 4; + } + } + + if (cflags & C_IMM16) { + if (hs->flags & F_IMM32) { + hs->flags |= F_IMM16; + hs->disp.disp16 = *(uint16_t *)p; + } else if (hs->flags & F_IMM16) { + hs->flags |= F_2IMM16; + hs->disp.disp16 = *(uint16_t *)p; + } else { + hs->flags |= F_IMM16; + hs->imm.imm16 = *(uint16_t *)p; + } + p += 2; + } + if (cflags & C_IMM8) { + hs->flags |= F_IMM8; + hs->imm.imm8 = *p++; + } + + if (cflags & C_REL32) { + rel32_ok: + hs->flags |= F_IMM32 | F_RELATIVE; + hs->imm.imm32 = *(uint32_t *)p; + p += 4; + } else if (cflags & C_REL8) { + hs->flags |= F_IMM8 | F_RELATIVE; + hs->imm.imm8 = *p++; + } + + disasm_done: + + if ((hs->len = (uint8_t)(p-(uint8_t *)code)) > 15) { + hs->flags |= F_ERROR | F_ERROR_LENGTH; + hs->len = 15; + } + + return (unsigned int)hs->len; +} + +#endif // defined(_M_IX86) || defined(__i386__) diff --git a/galliumhook/minhook-multihook/src/hde/hde32.h b/galliumhook/minhook-multihook/src/hde/hde32.h new file mode 100644 index 0000000..1112450 --- /dev/null +++ b/galliumhook/minhook-multihook/src/hde/hde32.h @@ -0,0 +1,105 @@ +/* + * Hacker Disassembler Engine 32 + * Copyright (c) 2006-2009, Vyacheslav Patkov. + * All rights reserved. + * + * hde32.h: C/C++ header file + * + */ + +#ifndef _HDE32_H_ +#define _HDE32_H_ + +/* stdint.h - C99 standard header + * http://en.wikipedia.org/wiki/stdint.h + * + * if your compiler doesn't contain "stdint.h" header (for + * example, Microsoft Visual C++), you can download file: + * http://www.azillionmonkeys.com/qed/pstdint.h + * and change next line to: + * #include "pstdint.h" + */ +#include "pstdint.h" + +#define F_MODRM 0x00000001 +#define F_SIB 0x00000002 +#define F_IMM8 0x00000004 +#define F_IMM16 0x00000008 +#define F_IMM32 0x00000010 +#define F_DISP8 0x00000020 +#define F_DISP16 0x00000040 +#define F_DISP32 0x00000080 +#define F_RELATIVE 0x00000100 +#define F_2IMM16 0x00000800 +#define F_ERROR 0x00001000 +#define F_ERROR_OPCODE 0x00002000 +#define F_ERROR_LENGTH 0x00004000 +#define F_ERROR_LOCK 0x00008000 +#define F_ERROR_OPERAND 0x00010000 +#define F_PREFIX_REPNZ 0x01000000 +#define F_PREFIX_REPX 0x02000000 +#define F_PREFIX_REP 0x03000000 +#define F_PREFIX_66 0x04000000 +#define F_PREFIX_67 0x08000000 +#define F_PREFIX_LOCK 0x10000000 +#define F_PREFIX_SEG 0x20000000 +#define F_PREFIX_ANY 0x3f000000 + +#define PREFIX_SEGMENT_CS 0x2e +#define PREFIX_SEGMENT_SS 0x36 +#define PREFIX_SEGMENT_DS 0x3e +#define PREFIX_SEGMENT_ES 0x26 +#define PREFIX_SEGMENT_FS 0x64 +#define PREFIX_SEGMENT_GS 0x65 +#define PREFIX_LOCK 0xf0 +#define PREFIX_REPNZ 0xf2 +#define PREFIX_REPX 0xf3 +#define PREFIX_OPERAND_SIZE 0x66 +#define PREFIX_ADDRESS_SIZE 0x67 + +#pragma pack(push,1) + +typedef struct { + uint8_t len; + uint8_t p_rep; + uint8_t p_lock; + uint8_t p_seg; + uint8_t p_66; + uint8_t p_67; + uint8_t opcode; + uint8_t opcode2; + uint8_t modrm; + uint8_t modrm_mod; + uint8_t modrm_reg; + uint8_t modrm_rm; + uint8_t sib; + uint8_t sib_scale; + uint8_t sib_index; + uint8_t sib_base; + union { + uint8_t imm8; + uint16_t imm16; + uint32_t imm32; + } imm; + union { + uint8_t disp8; + uint16_t disp16; + uint32_t disp32; + } disp; + uint32_t flags; +} hde32s; + +#pragma pack(pop) + +#ifdef __cplusplus +extern "C" { +#endif + +/* __cdecl */ +unsigned int hde32_disasm(const void *code, hde32s *hs); + +#ifdef __cplusplus +} +#endif + +#endif /* _HDE32_H_ */ diff --git a/galliumhook/minhook-multihook/src/hde/hde64.c b/galliumhook/minhook-multihook/src/hde/hde64.c new file mode 100644 index 0000000..55a702e --- /dev/null +++ b/galliumhook/minhook-multihook/src/hde/hde64.c @@ -0,0 +1,333 @@ +/* + * Hacker Disassembler Engine 64 C + * Copyright (c) 2008-2009, Vyacheslav Patkov. + * All rights reserved. + * + */ + +#if defined(_M_X64) || defined(__x86_64__) + +#include +#include "hde64.h" +#include "table64.h" + +unsigned int hde64_disasm(const void *code, hde64s *hs) +{ + uint8_t x, c, *p = (uint8_t *)code, cflags, opcode, pref = 0; + uint8_t *ht = hde64_table, m_mod, m_reg, m_rm, disp_size = 0; + uint8_t op64 = 0; + + memset(hs, 0, sizeof(hde64s)); + + for (x = 16; x; x--) + switch (c = *p++) { + case 0xf3: + hs->p_rep = c; + pref |= PRE_F3; + break; + case 0xf2: + hs->p_rep = c; + pref |= PRE_F2; + break; + case 0xf0: + hs->p_lock = c; + pref |= PRE_LOCK; + break; + case 0x26: case 0x2e: case 0x36: + case 0x3e: case 0x64: case 0x65: + hs->p_seg = c; + pref |= PRE_SEG; + break; + case 0x66: + hs->p_66 = c; + pref |= PRE_66; + break; + case 0x67: + hs->p_67 = c; + pref |= PRE_67; + break; + default: + goto pref_done; + } + pref_done: + + hs->flags = (uint32_t)pref << 23; + + if (!pref) + pref |= PRE_NONE; + + if ((c & 0xf0) == 0x40) { + hs->flags |= F_PREFIX_REX; + if ((hs->rex_w = (c & 0xf) >> 3) && (*p & 0xf8) == 0xb8) + op64++; + hs->rex_r = (c & 7) >> 2; + hs->rex_x = (c & 3) >> 1; + hs->rex_b = c & 1; + if (((c = *p++) & 0xf0) == 0x40) { + opcode = c; + goto error_opcode; + } + } + + if ((hs->opcode = c) == 0x0f) { + hs->opcode2 = c = *p++; + ht += DELTA_OPCODES; + } else if (c >= 0xa0 && c <= 0xa3) { + op64++; + if (pref & PRE_67) + pref |= PRE_66; + else + pref &= ~PRE_66; + } + + opcode = c; + cflags = ht[ht[opcode / 4] + (opcode % 4)]; + + if (cflags == C_ERROR) { + error_opcode: + hs->flags |= F_ERROR | F_ERROR_OPCODE; + cflags = 0; + if ((opcode & -3) == 0x24) + cflags++; + } + + x = 0; + if (cflags & C_GROUP) { + uint16_t t; + t = *(uint16_t *)(ht + (cflags & 0x7f)); + cflags = (uint8_t)t; + x = (uint8_t)(t >> 8); + } + + if (hs->opcode2) { + ht = hde64_table + DELTA_PREFIXES; + if (ht[ht[opcode / 4] + (opcode % 4)] & pref) + hs->flags |= F_ERROR | F_ERROR_OPCODE; + } + + if (cflags & C_MODRM) { + hs->flags |= F_MODRM; + hs->modrm = c = *p++; + hs->modrm_mod = m_mod = c >> 6; + hs->modrm_rm = m_rm = c & 7; + hs->modrm_reg = m_reg = (c & 0x3f) >> 3; + + if (x && ((x << m_reg) & 0x80)) + hs->flags |= F_ERROR | F_ERROR_OPCODE; + + if (!hs->opcode2 && opcode >= 0xd9 && opcode <= 0xdf) { + uint8_t t = opcode - 0xd9; + if (m_mod == 3) { + ht = hde64_table + DELTA_FPU_MODRM + t*8; + t = ht[m_reg] << m_rm; + } else { + ht = hde64_table + DELTA_FPU_REG; + t = ht[t] << m_reg; + } + if (t & 0x80) + hs->flags |= F_ERROR | F_ERROR_OPCODE; + } + + if (pref & PRE_LOCK) { + if (m_mod == 3) { + hs->flags |= F_ERROR | F_ERROR_LOCK; + } else { + uint8_t *table_end, op = opcode; + if (hs->opcode2) { + ht = hde64_table + DELTA_OP2_LOCK_OK; + table_end = ht + DELTA_OP_ONLY_MEM - DELTA_OP2_LOCK_OK; + } else { + ht = hde64_table + DELTA_OP_LOCK_OK; + table_end = ht + DELTA_OP2_LOCK_OK - DELTA_OP_LOCK_OK; + op &= -2; + } + for (; ht != table_end; ht++) + if (*ht++ == op) { + if (!((*ht << m_reg) & 0x80)) + goto no_lock_error; + else + break; + } + hs->flags |= F_ERROR | F_ERROR_LOCK; + no_lock_error: + ; + } + } + + if (hs->opcode2) { + switch (opcode) { + case 0x20: case 0x22: + m_mod = 3; + if (m_reg > 4 || m_reg == 1) + goto error_operand; + else + goto no_error_operand; + case 0x21: case 0x23: + m_mod = 3; + if (m_reg == 4 || m_reg == 5) + goto error_operand; + else + goto no_error_operand; + } + } else { + switch (opcode) { + case 0x8c: + if (m_reg > 5) + goto error_operand; + else + goto no_error_operand; + case 0x8e: + if (m_reg == 1 || m_reg > 5) + goto error_operand; + else + goto no_error_operand; + } + } + + if (m_mod == 3) { + uint8_t *table_end; + if (hs->opcode2) { + ht = hde64_table + DELTA_OP2_ONLY_MEM; + table_end = ht + sizeof(hde64_table) - DELTA_OP2_ONLY_MEM; + } else { + ht = hde64_table + DELTA_OP_ONLY_MEM; + table_end = ht + DELTA_OP2_ONLY_MEM - DELTA_OP_ONLY_MEM; + } + for (; ht != table_end; ht += 2) + if (*ht++ == opcode) { + if (*ht++ & pref && !((*ht << m_reg) & 0x80)) + goto error_operand; + else + break; + } + goto no_error_operand; + } else if (hs->opcode2) { + switch (opcode) { + case 0x50: case 0xd7: case 0xf7: + if (pref & (PRE_NONE | PRE_66)) + goto error_operand; + break; + case 0xd6: + if (pref & (PRE_F2 | PRE_F3)) + goto error_operand; + break; + case 0xc5: + goto error_operand; + } + goto no_error_operand; + } else + goto no_error_operand; + + error_operand: + hs->flags |= F_ERROR | F_ERROR_OPERAND; + no_error_operand: + + c = *p++; + if (m_reg <= 1) { + if (opcode == 0xf6) + cflags |= C_IMM8; + else if (opcode == 0xf7) + cflags |= C_IMM_P66; + } + + switch (m_mod) { + case 0: + if (pref & PRE_67) { + if (m_rm == 6) + disp_size = 2; + } else + if (m_rm == 5) + disp_size = 4; + break; + case 1: + disp_size = 1; + break; + case 2: + disp_size = 2; + if (!(pref & PRE_67)) + disp_size <<= 1; + } + + if (m_mod != 3 && m_rm == 4) { + hs->flags |= F_SIB; + p++; + hs->sib = c; + hs->sib_scale = c >> 6; + hs->sib_index = (c & 0x3f) >> 3; + if ((hs->sib_base = c & 7) == 5 && !(m_mod & 1)) + disp_size = 4; + } + + p--; + switch (disp_size) { + case 1: + hs->flags |= F_DISP8; + hs->disp.disp8 = *p; + break; + case 2: + hs->flags |= F_DISP16; + hs->disp.disp16 = *(uint16_t *)p; + break; + case 4: + hs->flags |= F_DISP32; + hs->disp.disp32 = *(uint32_t *)p; + } + p += disp_size; + } else if (pref & PRE_LOCK) + hs->flags |= F_ERROR | F_ERROR_LOCK; + + if (cflags & C_IMM_P66) { + if (cflags & C_REL32) { + if (pref & PRE_66) { + hs->flags |= F_IMM16 | F_RELATIVE; + hs->imm.imm16 = *(uint16_t *)p; + p += 2; + goto disasm_done; + } + goto rel32_ok; + } + if (op64) { + hs->flags |= F_IMM64; + hs->imm.imm64 = *(uint64_t *)p; + p += 8; + } else if (!(pref & PRE_66)) { + hs->flags |= F_IMM32; + hs->imm.imm32 = *(uint32_t *)p; + p += 4; + } else + goto imm16_ok; + } + + + if (cflags & C_IMM16) { + imm16_ok: + hs->flags |= F_IMM16; + hs->imm.imm16 = *(uint16_t *)p; + p += 2; + } + if (cflags & C_IMM8) { + hs->flags |= F_IMM8; + hs->imm.imm8 = *p++; + } + + if (cflags & C_REL32) { + rel32_ok: + hs->flags |= F_IMM32 | F_RELATIVE; + hs->imm.imm32 = *(uint32_t *)p; + p += 4; + } else if (cflags & C_REL8) { + hs->flags |= F_IMM8 | F_RELATIVE; + hs->imm.imm8 = *p++; + } + + disasm_done: + + if ((hs->len = (uint8_t)(p-(uint8_t *)code)) > 15) { + hs->flags |= F_ERROR | F_ERROR_LENGTH; + hs->len = 15; + } + + return (unsigned int)hs->len; +} + +#endif // defined(_M_X64) || defined(__x86_64__) diff --git a/galliumhook/minhook-multihook/src/hde/hde64.h b/galliumhook/minhook-multihook/src/hde/hde64.h new file mode 100644 index 0000000..ecbf4df --- /dev/null +++ b/galliumhook/minhook-multihook/src/hde/hde64.h @@ -0,0 +1,112 @@ +/* + * Hacker Disassembler Engine 64 + * Copyright (c) 2008-2009, Vyacheslav Patkov. + * All rights reserved. + * + * hde64.h: C/C++ header file + * + */ + +#ifndef _HDE64_H_ +#define _HDE64_H_ + +/* stdint.h - C99 standard header + * http://en.wikipedia.org/wiki/stdint.h + * + * if your compiler doesn't contain "stdint.h" header (for + * example, Microsoft Visual C++), you can download file: + * http://www.azillionmonkeys.com/qed/pstdint.h + * and change next line to: + * #include "pstdint.h" + */ +#include "pstdint.h" + +#define F_MODRM 0x00000001 +#define F_SIB 0x00000002 +#define F_IMM8 0x00000004 +#define F_IMM16 0x00000008 +#define F_IMM32 0x00000010 +#define F_IMM64 0x00000020 +#define F_DISP8 0x00000040 +#define F_DISP16 0x00000080 +#define F_DISP32 0x00000100 +#define F_RELATIVE 0x00000200 +#define F_ERROR 0x00001000 +#define F_ERROR_OPCODE 0x00002000 +#define F_ERROR_LENGTH 0x00004000 +#define F_ERROR_LOCK 0x00008000 +#define F_ERROR_OPERAND 0x00010000 +#define F_PREFIX_REPNZ 0x01000000 +#define F_PREFIX_REPX 0x02000000 +#define F_PREFIX_REP 0x03000000 +#define F_PREFIX_66 0x04000000 +#define F_PREFIX_67 0x08000000 +#define F_PREFIX_LOCK 0x10000000 +#define F_PREFIX_SEG 0x20000000 +#define F_PREFIX_REX 0x40000000 +#define F_PREFIX_ANY 0x7f000000 + +#define PREFIX_SEGMENT_CS 0x2e +#define PREFIX_SEGMENT_SS 0x36 +#define PREFIX_SEGMENT_DS 0x3e +#define PREFIX_SEGMENT_ES 0x26 +#define PREFIX_SEGMENT_FS 0x64 +#define PREFIX_SEGMENT_GS 0x65 +#define PREFIX_LOCK 0xf0 +#define PREFIX_REPNZ 0xf2 +#define PREFIX_REPX 0xf3 +#define PREFIX_OPERAND_SIZE 0x66 +#define PREFIX_ADDRESS_SIZE 0x67 + +#pragma pack(push,1) + +typedef struct { + uint8_t len; + uint8_t p_rep; + uint8_t p_lock; + uint8_t p_seg; + uint8_t p_66; + uint8_t p_67; + uint8_t rex; + uint8_t rex_w; + uint8_t rex_r; + uint8_t rex_x; + uint8_t rex_b; + uint8_t opcode; + uint8_t opcode2; + uint8_t modrm; + uint8_t modrm_mod; + uint8_t modrm_reg; + uint8_t modrm_rm; + uint8_t sib; + uint8_t sib_scale; + uint8_t sib_index; + uint8_t sib_base; + union { + uint8_t imm8; + uint16_t imm16; + uint32_t imm32; + uint64_t imm64; + } imm; + union { + uint8_t disp8; + uint16_t disp16; + uint32_t disp32; + } disp; + uint32_t flags; +} hde64s; + +#pragma pack(pop) + +#ifdef __cplusplus +extern "C" { +#endif + +/* __cdecl */ +unsigned int hde64_disasm(const void *code, hde64s *hs); + +#ifdef __cplusplus +} +#endif + +#endif /* _HDE64_H_ */ diff --git a/galliumhook/minhook-multihook/src/hde/pstdint.h b/galliumhook/minhook-multihook/src/hde/pstdint.h new file mode 100644 index 0000000..84d82a0 --- /dev/null +++ b/galliumhook/minhook-multihook/src/hde/pstdint.h @@ -0,0 +1,39 @@ +/* + * MinHook - The Minimalistic API Hooking Library for x64/x86 + * Copyright (C) 2009-2017 Tsuda Kageyu. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include + +// Integer types for HDE. +typedef INT8 int8_t; +typedef INT16 int16_t; +typedef INT32 int32_t; +typedef INT64 int64_t; +typedef UINT8 uint8_t; +typedef UINT16 uint16_t; +typedef UINT32 uint32_t; +typedef UINT64 uint64_t; diff --git a/galliumhook/minhook-multihook/src/hde/table32.h b/galliumhook/minhook-multihook/src/hde/table32.h new file mode 100644 index 0000000..7b3e12e --- /dev/null +++ b/galliumhook/minhook-multihook/src/hde/table32.h @@ -0,0 +1,73 @@ +/* + * Hacker Disassembler Engine 32 C + * Copyright (c) 2008-2009, Vyacheslav Patkov. + * All rights reserved. + * + */ + +#define C_NONE 0x00 +#define C_MODRM 0x01 +#define C_IMM8 0x02 +#define C_IMM16 0x04 +#define C_IMM_P66 0x10 +#define C_REL8 0x20 +#define C_REL32 0x40 +#define C_GROUP 0x80 +#define C_ERROR 0xff + +#define PRE_ANY 0x00 +#define PRE_NONE 0x01 +#define PRE_F2 0x02 +#define PRE_F3 0x04 +#define PRE_66 0x08 +#define PRE_67 0x10 +#define PRE_LOCK 0x20 +#define PRE_SEG 0x40 +#define PRE_ALL 0xff + +#define DELTA_OPCODES 0x4a +#define DELTA_FPU_REG 0xf1 +#define DELTA_FPU_MODRM 0xf8 +#define DELTA_PREFIXES 0x130 +#define DELTA_OP_LOCK_OK 0x1a1 +#define DELTA_OP2_LOCK_OK 0x1b9 +#define DELTA_OP_ONLY_MEM 0x1cb +#define DELTA_OP2_ONLY_MEM 0x1da + +unsigned char hde32_table[] = { + 0xa3,0xa8,0xa3,0xa8,0xa3,0xa8,0xa3,0xa8,0xa3,0xa8,0xa3,0xa8,0xa3,0xa8,0xa3, + 0xa8,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xac,0xaa,0xb2,0xaa,0x9f,0x9f, + 0x9f,0x9f,0xb5,0xa3,0xa3,0xa4,0xaa,0xaa,0xba,0xaa,0x96,0xaa,0xa8,0xaa,0xc3, + 0xc3,0x96,0x96,0xb7,0xae,0xd6,0xbd,0xa3,0xc5,0xa3,0xa3,0x9f,0xc3,0x9c,0xaa, + 0xaa,0xac,0xaa,0xbf,0x03,0x7f,0x11,0x7f,0x01,0x7f,0x01,0x3f,0x01,0x01,0x90, + 0x82,0x7d,0x97,0x59,0x59,0x59,0x59,0x59,0x7f,0x59,0x59,0x60,0x7d,0x7f,0x7f, + 0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x9a,0x88,0x7d, + 0x59,0x50,0x50,0x50,0x50,0x59,0x59,0x59,0x59,0x61,0x94,0x61,0x9e,0x59,0x59, + 0x85,0x59,0x92,0xa3,0x60,0x60,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59, + 0x59,0x59,0x9f,0x01,0x03,0x01,0x04,0x03,0xd5,0x03,0xcc,0x01,0xbc,0x03,0xf0, + 0x10,0x10,0x10,0x10,0x50,0x50,0x50,0x50,0x14,0x20,0x20,0x20,0x20,0x01,0x01, + 0x01,0x01,0xc4,0x02,0x10,0x00,0x00,0x00,0x00,0x01,0x01,0xc0,0xc2,0x10,0x11, + 0x02,0x03,0x11,0x03,0x03,0x04,0x00,0x00,0x14,0x00,0x02,0x00,0x00,0xc6,0xc8, + 0x02,0x02,0x02,0x02,0x00,0x00,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0xff,0xca, + 0x01,0x01,0x01,0x00,0x06,0x00,0x04,0x00,0xc0,0xc2,0x01,0x01,0x03,0x01,0xff, + 0xff,0x01,0x00,0x03,0xc4,0xc4,0xc6,0x03,0x01,0x01,0x01,0xff,0x03,0x03,0x03, + 0xc8,0x40,0x00,0x0a,0x00,0x04,0x00,0x00,0x00,0x00,0x7f,0x00,0x33,0x01,0x00, + 0x00,0x00,0x00,0x00,0x00,0xff,0xbf,0xff,0xff,0x00,0x00,0x00,0x00,0x07,0x00, + 0x00,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0xff,0xff,0x00,0x00,0x00,0xbf,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x7f,0x00,0x00,0xff,0x4a,0x4a,0x4a,0x4a,0x4b,0x52,0x4a,0x4a,0x4a,0x4a,0x4f, + 0x4c,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x55,0x45,0x40,0x4a,0x4a,0x4a, + 0x45,0x59,0x4d,0x46,0x4a,0x5d,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a, + 0x4a,0x4a,0x4a,0x4a,0x4a,0x61,0x63,0x67,0x4e,0x4a,0x4a,0x6b,0x6d,0x4a,0x4a, + 0x45,0x6d,0x4a,0x4a,0x44,0x45,0x4a,0x4a,0x00,0x00,0x00,0x02,0x0d,0x06,0x06, + 0x06,0x06,0x0e,0x00,0x00,0x00,0x00,0x06,0x06,0x06,0x00,0x06,0x06,0x02,0x06, + 0x00,0x0a,0x0a,0x07,0x07,0x06,0x02,0x05,0x05,0x02,0x02,0x00,0x00,0x04,0x04, + 0x04,0x04,0x00,0x00,0x00,0x0e,0x05,0x06,0x06,0x06,0x01,0x06,0x00,0x00,0x08, + 0x00,0x10,0x00,0x18,0x00,0x20,0x00,0x28,0x00,0x30,0x00,0x80,0x01,0x82,0x01, + 0x86,0x00,0xf6,0xcf,0xfe,0x3f,0xab,0x00,0xb0,0x00,0xb1,0x00,0xb3,0x00,0xba, + 0xf8,0xbb,0x00,0xc0,0x00,0xc1,0x00,0xc7,0xbf,0x62,0xff,0x00,0x8d,0xff,0x00, + 0xc4,0xff,0x00,0xc5,0xff,0x00,0xff,0xff,0xeb,0x01,0xff,0x0e,0x12,0x08,0x00, + 0x13,0x09,0x00,0x16,0x08,0x00,0x17,0x09,0x00,0x2b,0x09,0x00,0xae,0xff,0x07, + 0xb2,0xff,0x00,0xb4,0xff,0x00,0xb5,0xff,0x00,0xc3,0x01,0x00,0xc7,0xff,0xbf, + 0xe7,0x08,0x00,0xf0,0x02,0x00 +}; diff --git a/galliumhook/minhook-multihook/src/hde/table64.h b/galliumhook/minhook-multihook/src/hde/table64.h new file mode 100644 index 0000000..01d4541 --- /dev/null +++ b/galliumhook/minhook-multihook/src/hde/table64.h @@ -0,0 +1,74 @@ +/* + * Hacker Disassembler Engine 64 C + * Copyright (c) 2008-2009, Vyacheslav Patkov. + * All rights reserved. + * + */ + +#define C_NONE 0x00 +#define C_MODRM 0x01 +#define C_IMM8 0x02 +#define C_IMM16 0x04 +#define C_IMM_P66 0x10 +#define C_REL8 0x20 +#define C_REL32 0x40 +#define C_GROUP 0x80 +#define C_ERROR 0xff + +#define PRE_ANY 0x00 +#define PRE_NONE 0x01 +#define PRE_F2 0x02 +#define PRE_F3 0x04 +#define PRE_66 0x08 +#define PRE_67 0x10 +#define PRE_LOCK 0x20 +#define PRE_SEG 0x40 +#define PRE_ALL 0xff + +#define DELTA_OPCODES 0x4a +#define DELTA_FPU_REG 0xfd +#define DELTA_FPU_MODRM 0x104 +#define DELTA_PREFIXES 0x13c +#define DELTA_OP_LOCK_OK 0x1ae +#define DELTA_OP2_LOCK_OK 0x1c6 +#define DELTA_OP_ONLY_MEM 0x1d8 +#define DELTA_OP2_ONLY_MEM 0x1e7 + +unsigned char hde64_table[] = { + 0xa5,0xaa,0xa5,0xb8,0xa5,0xaa,0xa5,0xaa,0xa5,0xb8,0xa5,0xb8,0xa5,0xb8,0xa5, + 0xb8,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xac,0xc0,0xcc,0xc0,0xa1,0xa1, + 0xa1,0xa1,0xb1,0xa5,0xa5,0xa6,0xc0,0xc0,0xd7,0xda,0xe0,0xc0,0xe4,0xc0,0xea, + 0xea,0xe0,0xe0,0x98,0xc8,0xee,0xf1,0xa5,0xd3,0xa5,0xa5,0xa1,0xea,0x9e,0xc0, + 0xc0,0xc2,0xc0,0xe6,0x03,0x7f,0x11,0x7f,0x01,0x7f,0x01,0x3f,0x01,0x01,0xab, + 0x8b,0x90,0x64,0x5b,0x5b,0x5b,0x5b,0x5b,0x92,0x5b,0x5b,0x76,0x90,0x92,0x92, + 0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x6a,0x73,0x90, + 0x5b,0x52,0x52,0x52,0x52,0x5b,0x5b,0x5b,0x5b,0x77,0x7c,0x77,0x85,0x5b,0x5b, + 0x70,0x5b,0x7a,0xaf,0x76,0x76,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b, + 0x5b,0x5b,0x86,0x01,0x03,0x01,0x04,0x03,0xd5,0x03,0xd5,0x03,0xcc,0x01,0xbc, + 0x03,0xf0,0x03,0x03,0x04,0x00,0x50,0x50,0x50,0x50,0xff,0x20,0x20,0x20,0x20, + 0x01,0x01,0x01,0x01,0xc4,0x02,0x10,0xff,0xff,0xff,0x01,0x00,0x03,0x11,0xff, + 0x03,0xc4,0xc6,0xc8,0x02,0x10,0x00,0xff,0xcc,0x01,0x01,0x01,0x00,0x00,0x00, + 0x00,0x01,0x01,0x03,0x01,0xff,0xff,0xc0,0xc2,0x10,0x11,0x02,0x03,0x01,0x01, + 0x01,0xff,0xff,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0xff,0xff,0xff,0xff,0x10, + 0x10,0x10,0x10,0x02,0x10,0x00,0x00,0xc6,0xc8,0x02,0x02,0x02,0x02,0x06,0x00, + 0x04,0x00,0x02,0xff,0x00,0xc0,0xc2,0x01,0x01,0x03,0x03,0x03,0xca,0x40,0x00, + 0x0a,0x00,0x04,0x00,0x00,0x00,0x00,0x7f,0x00,0x33,0x01,0x00,0x00,0x00,0x00, + 0x00,0x00,0xff,0xbf,0xff,0xff,0x00,0x00,0x00,0x00,0x07,0x00,0x00,0xff,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff, + 0x00,0x00,0x00,0xbf,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7f,0x00,0x00, + 0xff,0x40,0x40,0x40,0x40,0x41,0x49,0x40,0x40,0x40,0x40,0x4c,0x42,0x40,0x40, + 0x40,0x40,0x40,0x40,0x40,0x40,0x4f,0x44,0x53,0x40,0x40,0x40,0x44,0x57,0x43, + 0x5c,0x40,0x60,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40, + 0x40,0x40,0x64,0x66,0x6e,0x6b,0x40,0x40,0x6a,0x46,0x40,0x40,0x44,0x46,0x40, + 0x40,0x5b,0x44,0x40,0x40,0x00,0x00,0x00,0x00,0x06,0x06,0x06,0x06,0x01,0x06, + 0x06,0x02,0x06,0x06,0x00,0x06,0x00,0x0a,0x0a,0x00,0x00,0x00,0x02,0x07,0x07, + 0x06,0x02,0x0d,0x06,0x06,0x06,0x0e,0x05,0x05,0x02,0x02,0x00,0x00,0x04,0x04, + 0x04,0x04,0x05,0x06,0x06,0x06,0x00,0x00,0x00,0x0e,0x00,0x00,0x08,0x00,0x10, + 0x00,0x18,0x00,0x20,0x00,0x28,0x00,0x30,0x00,0x80,0x01,0x82,0x01,0x86,0x00, + 0xf6,0xcf,0xfe,0x3f,0xab,0x00,0xb0,0x00,0xb1,0x00,0xb3,0x00,0xba,0xf8,0xbb, + 0x00,0xc0,0x00,0xc1,0x00,0xc7,0xbf,0x62,0xff,0x00,0x8d,0xff,0x00,0xc4,0xff, + 0x00,0xc5,0xff,0x00,0xff,0xff,0xeb,0x01,0xff,0x0e,0x12,0x08,0x00,0x13,0x09, + 0x00,0x16,0x08,0x00,0x17,0x09,0x00,0x2b,0x09,0x00,0xae,0xff,0x07,0xb2,0xff, + 0x00,0xb4,0xff,0x00,0xb5,0xff,0x00,0xc3,0x01,0x00,0xc7,0xff,0xbf,0xe7,0x08, + 0x00,0xf0,0x02,0x00 +}; diff --git a/galliumhook/minhook-multihook/src/hook.c b/galliumhook/minhook-multihook/src/hook.c new file mode 100644 index 0000000..2d4e642 --- /dev/null +++ b/galliumhook/minhook-multihook/src/hook.c @@ -0,0 +1,1180 @@ +/* + * MinHook - The Minimalistic API Hooking Library for x64/x86 + * Copyright (C) 2009-2017 Tsuda Kageyu. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include + +#include "../include/MinHook.h" +#include "buffer.h" +#include "trampoline.h" + +#ifndef ARRAYSIZE + #define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0])) +#endif + +// Initial capacity of the HOOK_ENTRY buffer. +#define INITIAL_HOOK_CAPACITY 32 + +// Initial capacity of the thread IDs buffer. +#define INITIAL_THREAD_CAPACITY 128 + +// Special hook position values. +#define INVALID_HOOK_POS UINT_MAX + +// Thread access rights for suspending/resuming threads. +#define THREAD_ACCESS \ + (THREAD_SUSPEND_RESUME | THREAD_GET_CONTEXT | THREAD_QUERY_INFORMATION | THREAD_SET_CONTEXT) + +// Suspended threads for Freeze()/Unfreeze(). +typedef struct _FROZEN_THREADS +{ + LPHANDLE pItems; // Data heap + UINT capacity; // Size of allocated data heap, items + UINT size; // Actual number of data items +} FROZEN_THREADS, *PFROZEN_THREADS; + +// Thread freeze related definitions. +typedef NTSTATUS(NTAPI* NtGetNextThread_t)( + _In_ HANDLE ProcessHandle, + _In_opt_ HANDLE ThreadHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ ULONG HandleAttributes, + _In_ ULONG Flags, + _Out_ PHANDLE NewThreadHandle + ); + +#ifndef STATUS_NO_MORE_ENTRIES +#define STATUS_NO_MORE_ENTRIES ((NTSTATUS)0x8000001AL) +#endif + +#ifndef NT_SUCCESS +#define NT_SUCCESS(Status) ((NTSTATUS)(Status) >= 0) +#endif + +// Function and function pointer declarations. +typedef MH_STATUS(WINAPI *ENABLE_HOOK_LL_PROC)(UINT pos, BOOL enable, PFROZEN_THREADS pThreads); +typedef MH_STATUS(WINAPI *DISABLE_HOOK_CHAIN_PROC)(ULONG_PTR hookIdent, LPVOID pTarget, UINT parentPos, ENABLE_HOOK_LL_PROC ParentEnableHookLL, PFROZEN_THREADS pThreads); + +static MH_STATUS WINAPI DisableHookChain(ULONG_PTR hookIdent, LPVOID pTarget, UINT parentPos, ENABLE_HOOK_LL_PROC ParentEnableHookLL, PFROZEN_THREADS pThreads); + +// Executable buffer of a hook. +typedef struct _EXEC_BUFFER +{ + DISABLE_HOOK_CHAIN_PROC pDisableHookChain; + ULONG_PTR hookIdent; + JMP_RELAY jmpRelay; + UINT8 trampoline[1]; // Uses the rest of the MEMORY_SLOT_SIZE bytes. +} EXEC_BUFFER, *PEXEC_BUFFER; + +// Hook information. +typedef struct _HOOK_ENTRY +{ + ULONG_PTR hookIdent; // Hook identifier, allows to hook the same function multiple times with different identifiers. + + LPVOID pTarget; // Address of the target function. + LPVOID pDetour; // Address of the detour function. + PEXEC_BUFFER pExecBuffer; // Address of the executable buffer for relay and trampoline. + UINT8 backup[8]; // Original prologue of the target function. + + UINT8 patchAbove : 1; // Uses the hot patch area. + UINT8 isEnabled : 1; // Enabled. + UINT8 queueEnable : 1; // Queued for enabling/disabling when != isEnabled. + + UINT nIP : 4; // Count of the instruction boundaries. + UINT8 oldIPs[8]; // Instruction boundaries of the target function. + UINT8 newIPs[8]; // Instruction boundaries of the trampoline function. +} HOOK_ENTRY, *PHOOK_ENTRY; + +//------------------------------------------------------------------------- +// Global Variables: +//------------------------------------------------------------------------- + +// Mutex. If not NULL, this library is initialized. +HANDLE g_hMutex = NULL; + +// Private heap handle. +HANDLE g_hHeap; + +// Thread freeze related variables. +MH_THREAD_FREEZE_METHOD g_threadFreezeMethod = MH_FREEZE_METHOD_ORIGINAL; + +NtGetNextThread_t NtGetNextThread; + +// Hook entries. +struct +{ + PHOOK_ENTRY pItems; // Data heap + UINT capacity; // Size of allocated data heap, items + UINT size; // Actual number of data items +} g_hooks; + +//------------------------------------------------------------------------- +// Returns INVALID_HOOK_POS if not found. +static UINT FindHookEntry(ULONG_PTR hookIdent, LPVOID pTarget) +{ + UINT i; + for (i = 0; i < g_hooks.size; ++i) + { + PHOOK_ENTRY pHook = &g_hooks.pItems[i]; + if ((ULONG_PTR)hookIdent == (ULONG_PTR)pHook->hookIdent && (ULONG_PTR)pTarget == (ULONG_PTR)pHook->pTarget) + return i; + } + + return INVALID_HOOK_POS; +} + +//------------------------------------------------------------------------- +static PHOOK_ENTRY AddHookEntry() +{ + if (g_hooks.pItems == NULL) + { + g_hooks.capacity = INITIAL_HOOK_CAPACITY; + g_hooks.pItems = (PHOOK_ENTRY)HeapAlloc( + g_hHeap, 0, g_hooks.capacity * sizeof(HOOK_ENTRY)); + if (g_hooks.pItems == NULL) + return NULL; + } + else if (g_hooks.size >= g_hooks.capacity) + { + PHOOK_ENTRY p = (PHOOK_ENTRY)HeapReAlloc( + g_hHeap, 0, g_hooks.pItems, (g_hooks.capacity * 2) * sizeof(HOOK_ENTRY)); + if (p == NULL) + return NULL; + + g_hooks.capacity *= 2; + g_hooks.pItems = p; + } + + return &g_hooks.pItems[g_hooks.size++]; +} + +//------------------------------------------------------------------------- +static VOID DeleteHookEntry(UINT pos) +{ + if (pos < g_hooks.size - 1) + g_hooks.pItems[pos] = g_hooks.pItems[g_hooks.size - 1]; + + g_hooks.size--; + + if (g_hooks.capacity / 2 >= INITIAL_HOOK_CAPACITY && g_hooks.capacity / 2 >= g_hooks.size) + { + PHOOK_ENTRY p = (PHOOK_ENTRY)HeapReAlloc( + g_hHeap, 0, g_hooks.pItems, (g_hooks.capacity / 2) * sizeof(HOOK_ENTRY)); + if (p == NULL) + return; + + g_hooks.capacity /= 2; + g_hooks.pItems = p; + } +} + +//------------------------------------------------------------------------- +static DWORD_PTR FindOldIP(PHOOK_ENTRY pHook, DWORD_PTR ip) +{ + // In any of the jump locations: + // Target -> Hotpatch jump (if patchAbove) -> Relay jump + // Restore IP to the detour. This is required for consistent behavior + // as a part of a DisableHookChain call, otherwise, if IP is restored + // to the target, hooks that should be called may be skipped. + + if (ip == (DWORD_PTR)pHook->pTarget) + return (DWORD_PTR)pHook->pDetour; + + if (pHook->patchAbove && ip == ((DWORD_PTR)pHook->pTarget - sizeof(JMP_REL))) + return (DWORD_PTR)pHook->pDetour; + + if (ip == (DWORD_PTR)&pHook->pExecBuffer->jmpRelay) + return (DWORD_PTR)pHook->pDetour; + + UINT i; + for (i = 0; i < pHook->nIP; ++i) + { + if (ip == ((DWORD_PTR)pHook->pExecBuffer->trampoline + pHook->newIPs[i])) + return (DWORD_PTR)pHook->pTarget + pHook->oldIPs[i]; + } + + return 0; +} + +//------------------------------------------------------------------------- +static DWORD_PTR FindNewIP(PHOOK_ENTRY pHook, DWORD_PTR ip) +{ + UINT i; + for (i = 0; i < pHook->nIP; ++i) + { + if (ip == ((DWORD_PTR)pHook->pTarget + pHook->oldIPs[i])) + return (DWORD_PTR)pHook->pExecBuffer->trampoline + pHook->newIPs[i]; + } + + return 0; +} + +//------------------------------------------------------------------------- +static VOID ProcessThreadIPs(HANDLE hThread, UINT pos, BOOL enable) +{ + // If the thread suspended in the overwritten area, + // move IP to the proper address. + + CONTEXT c; +#if defined(_M_X64) || defined(__x86_64__) + DWORD64 *pIP = &c.Rip; +#else + DWORD *pIP = &c.Eip; +#endif + PHOOK_ENTRY pHook = &g_hooks.pItems[pos]; + DWORD_PTR ip; + + c.ContextFlags = CONTEXT_CONTROL; + if (!GetThreadContext(hThread, &c)) + return; + + if (enable) + ip = FindNewIP(pHook, *pIP); + else + ip = FindOldIP(pHook, *pIP); + + if (ip != 0) + { + *pIP = ip; + SetThreadContext(hThread, &c); + } +} + +//------------------------------------------------------------------------- +static BOOL EnumerateAndSuspendThreads(PFROZEN_THREADS pThreads) +{ + BOOL succeeded = FALSE; + + HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); + if (hSnapshot != INVALID_HANDLE_VALUE) + { + THREADENTRY32 te; + te.dwSize = sizeof(THREADENTRY32); + if (Thread32First(hSnapshot, &te)) + { + succeeded = TRUE; + do + { + if (te.dwSize >= (FIELD_OFFSET(THREADENTRY32, th32OwnerProcessID) + sizeof(DWORD)) + && te.th32OwnerProcessID == GetCurrentProcessId() + && te.th32ThreadID != GetCurrentThreadId()) + { + HANDLE hThread = OpenThread(THREAD_ACCESS, FALSE, te.th32ThreadID); + + if (hThread != NULL && SuspendThread(hThread) == (DWORD)-1) + { + CloseHandle(hThread); + hThread = NULL; + } + + if (hThread != NULL) + { + if (pThreads->pItems == NULL) + { + pThreads->capacity = INITIAL_THREAD_CAPACITY; + pThreads->pItems + = (LPHANDLE)HeapAlloc(g_hHeap, 0, pThreads->capacity * sizeof(HANDLE)); + if (pThreads->pItems == NULL) + succeeded = FALSE; + } + else if (pThreads->size >= pThreads->capacity) + { + pThreads->capacity *= 2; + LPHANDLE p = (LPHANDLE)HeapReAlloc( + g_hHeap, 0, pThreads->pItems, pThreads->capacity * sizeof(HANDLE)); + if (p) + pThreads->pItems = p; + else + succeeded = FALSE; + } + + if (!succeeded) + { + ResumeThread(hThread); + CloseHandle(hThread); + break; + } + + pThreads->pItems[pThreads->size++] = hThread; + } + } + + te.dwSize = sizeof(THREADENTRY32); + } while (Thread32Next(hSnapshot, &te)); + + if (succeeded && GetLastError() != ERROR_NO_MORE_FILES) + succeeded = FALSE; + + if (!succeeded && pThreads->pItems != NULL) + { + UINT i; + for (i = 0; i < pThreads->size; ++i) + { + ResumeThread(pThreads->pItems[i]); + CloseHandle(pThreads->pItems[i]); + } + + HeapFree(g_hHeap, 0, pThreads->pItems); + pThreads->pItems = NULL; + } + } + CloseHandle(hSnapshot); + } + + return succeeded; +} + +//------------------------------------------------------------------------- +static BOOL EnumerateAndSuspendThreadsFast(PFROZEN_THREADS pThreads) +{ + BOOL succeeded = TRUE; + + HANDLE hThread = NULL; + BOOL bClosePrevThread = FALSE; + while (1) + { + HANDLE hNextThread; + NTSTATUS status = NtGetNextThread(GetCurrentProcess(), hThread, THREAD_ACCESS, 0, 0, &hNextThread); + if (bClosePrevThread) + CloseHandle(hThread); + + if (!NT_SUCCESS(status)) + { + if (status != STATUS_NO_MORE_ENTRIES) + succeeded = FALSE; + break; + } + + hThread = hNextThread; + bClosePrevThread = TRUE; + + if (GetThreadId(hThread) == GetCurrentThreadId()) + continue; + + if (SuspendThread(hThread) == (DWORD)-1) + continue; + + bClosePrevThread = FALSE; + + if (pThreads->pItems == NULL) + { + pThreads->capacity = INITIAL_THREAD_CAPACITY; + pThreads->pItems + = (LPHANDLE)HeapAlloc(g_hHeap, 0, pThreads->capacity * sizeof(HANDLE)); + if (pThreads->pItems == NULL) + succeeded = FALSE; + } + else if (pThreads->size >= pThreads->capacity) + { + pThreads->capacity *= 2; + LPHANDLE p = (LPHANDLE)HeapReAlloc( + g_hHeap, 0, pThreads->pItems, pThreads->capacity * sizeof(HANDLE)); + if (p) + pThreads->pItems = p; + else + succeeded = FALSE; + } + + if (!succeeded) + { + ResumeThread(hThread); + CloseHandle(hThread); + break; + } + + // Perform a synchronous operation to make sure the thread really is suspended. + // https://devblogs.microsoft.com/oldnewthing/20150205-00/?p=44743 + CONTEXT c; + c.ContextFlags = CONTEXT_CONTROL; + GetThreadContext(hThread, &c); + + pThreads->pItems[pThreads->size++] = hThread; + } + + if (!succeeded && pThreads->pItems != NULL) + { + UINT i; + for (i = 0; i < pThreads->size; ++i) + { + ResumeThread(pThreads->pItems[i]); + CloseHandle(pThreads->pItems[i]); + } + + HeapFree(g_hHeap, 0, pThreads->pItems); + pThreads->pItems = NULL; + } + + return succeeded; +} + +//------------------------------------------------------------------------- +static VOID ProcessFrozenThreads(PFROZEN_THREADS pThreads, UINT pos, BOOL enable) +{ + if (pThreads->pItems != NULL) + { + UINT i; + for (i = 0; i < pThreads->size; ++i) + { + ProcessThreadIPs(pThreads->pItems[i], pos, enable); + } + } +} + +//------------------------------------------------------------------------- +static MH_STATUS Freeze(PFROZEN_THREADS pThreads) +{ + MH_STATUS status = MH_OK; + + pThreads->pItems = NULL; + pThreads->capacity = 0; + pThreads->size = 0; + + switch (g_threadFreezeMethod) + { + case MH_FREEZE_METHOD_ORIGINAL: + if (!EnumerateAndSuspendThreads(pThreads)) + status = MH_ERROR_MEMORY_ALLOC; + break; + + case MH_FREEZE_METHOD_FAST_UNDOCUMENTED: + if (!EnumerateAndSuspendThreadsFast(pThreads)) + status = MH_ERROR_MEMORY_ALLOC; + break; + + case MH_FREEZE_METHOD_NONE_UNSAFE: + // Nothing to do. + break; + } + + return status; +} + +//------------------------------------------------------------------------- +static VOID Unfreeze(PFROZEN_THREADS pThreads) +{ + if (pThreads->pItems != NULL) + { + UINT i; + for (i = 0; i < pThreads->size; ++i) + { + ResumeThread(pThreads->pItems[i]); + CloseHandle(pThreads->pItems[i]); + } + + HeapFree(g_hHeap, 0, pThreads->pItems); + } +} + +//------------------------------------------------------------------------- +static MH_STATUS CreateHookTrampoline(UINT pos) +{ + PHOOK_ENTRY pHook = &g_hooks.pItems[pos]; + + TRAMPOLINE ct; + ct.pTarget = pHook->pTarget; + ct.pTrampoline = pHook->pExecBuffer->trampoline; + ct.trampolineSize = MEMORY_SLOT_SIZE - offsetof(EXEC_BUFFER, trampoline); + if (!CreateTrampolineFunction(&ct)) + { + return MH_ERROR_UNSUPPORTED_FUNCTION; + } + + // Back up the target function. + if (ct.patchAbove) + { + memcpy( + pHook->backup, + (LPBYTE)pHook->pTarget - sizeof(JMP_REL), + sizeof(JMP_REL) + sizeof(JMP_REL_SHORT)); + } + else + { + memcpy(pHook->backup, pHook->pTarget, sizeof(JMP_REL)); + } + + pHook->patchAbove = ct.patchAbove; + pHook->nIP = ct.nIP; + memcpy(pHook->oldIPs, ct.oldIPs, ARRAYSIZE(ct.oldIPs)); + memcpy(pHook->newIPs, ct.newIPs, ARRAYSIZE(ct.newIPs)); + + return MH_OK; +} + +//------------------------------------------------------------------------- +static MH_STATUS WINAPI EnableHookLL(UINT pos, BOOL enable, PFROZEN_THREADS pThreads) +{ + PHOOK_ENTRY pHook = &g_hooks.pItems[pos]; + DWORD oldProtect; + SIZE_T patchSize = sizeof(JMP_REL); + LPBYTE pPatchTarget = (LPBYTE)pHook->pTarget; + + if (enable) + { + MH_STATUS status = CreateHookTrampoline(pos); + if (status != MH_OK) + return status; + } + + if (pHook->patchAbove) + { + pPatchTarget -= sizeof(JMP_REL); + patchSize += sizeof(JMP_REL_SHORT); + } + + if (!enable) + { + PJMP_REL pJmp = (PJMP_REL)pPatchTarget; + if (pJmp->opcode == 0xE9) + { + PJMP_RELAY pJmpRelay = (LPVOID)(((LPBYTE)pJmp + sizeof(JMP_REL)) + (INT32)pJmp->operand); + if (&pHook->pExecBuffer->jmpRelay != pJmpRelay) + { + PEXEC_BUFFER pOtherExecBuffer = (PEXEC_BUFFER)((LPBYTE)pJmpRelay - offsetof(EXEC_BUFFER, jmpRelay)); + return pOtherExecBuffer->pDisableHookChain(pOtherExecBuffer->hookIdent, pHook->pTarget, pos, EnableHookLL, pThreads); + } + } + } + + if (!VirtualProtect(pPatchTarget, patchSize, PAGE_EXECUTE_READWRITE, &oldProtect)) + return MH_ERROR_MEMORY_PROTECT; + + if (enable) + { + PJMP_REL pJmp = (PJMP_REL)pPatchTarget; + pJmp->opcode = 0xE9; + pJmp->operand = (UINT32)((LPBYTE)&pHook->pExecBuffer->jmpRelay - (pPatchTarget + sizeof(JMP_REL))); + + if (pHook->patchAbove) + { + PJMP_REL_SHORT pShortJmp = (PJMP_REL_SHORT)pHook->pTarget; + pShortJmp->opcode = 0xEB; + pShortJmp->operand = (UINT8)(0 - (sizeof(JMP_REL_SHORT) + sizeof(JMP_REL))); + } + } + else + { + if (pHook->patchAbove) + memcpy(pPatchTarget, pHook->backup, sizeof(JMP_REL) + sizeof(JMP_REL_SHORT)); + else + memcpy(pPatchTarget, pHook->backup, sizeof(JMP_REL)); + } + + VirtualProtect(pPatchTarget, patchSize, oldProtect, &oldProtect); + + // Just-in-case measure. + FlushInstructionCache(GetCurrentProcess(), pPatchTarget, patchSize); + + ProcessFrozenThreads(pThreads, pos, enable); + + pHook->isEnabled = enable; + pHook->queueEnable = enable; + + return MH_OK; +} + +//------------------------------------------------------------------------- +static MH_STATUS EnableHooksLL(BOOL bAllIdents, ULONG_PTR hookIdent, BOOL enable) +{ + MH_STATUS status = MH_OK; + UINT i, first = INVALID_HOOK_POS; + + for (i = 0; i < g_hooks.size; ++i) + { + PHOOK_ENTRY pHook = &g_hooks.pItems[i]; + if (pHook->isEnabled != enable && + (bAllIdents || pHook->hookIdent == hookIdent)) + { + first = i; + break; + } + } + + if (first != INVALID_HOOK_POS) + { + FROZEN_THREADS threads; + status = Freeze(&threads); + if (status == MH_OK) + { + for (i = first; i < g_hooks.size; ++i) + { + PHOOK_ENTRY pHook = &g_hooks.pItems[i]; + if (pHook->isEnabled != enable && + (bAllIdents || pHook->hookIdent == hookIdent)) + { + MH_STATUS enable_status = EnableHookLL(i, enable, &threads); + + // Instead of stopping on the first error, we enable as much + // hooks as we can, and return the last error, if any. + if (enable_status != MH_OK) + status = enable_status; + } + } + + Unfreeze(&threads); + } + } + + return status; +} + +//------------------------------------------------------------------------- +static MH_STATUS EnableAllHooksLL(BOOL enable) +{ + return EnableHooksLL(TRUE, 0, enable); +} + +//------------------------------------------------------------------------- +static HANDLE CreateProcessMutex(VOID) +{ + TCHAR szMutexName[sizeof("minhook_multihook_12345678")] = TEXT("minhook_multihook_"); + UINT mutexNameLen = sizeof("minhook_multihook_") - 1; + DWORD dw = GetCurrentProcessId(); + UINT i; + + // Build szMutexName in the following format: + // printf("minhook_multihook_%08X", GetCurrentProcessId()); + + for (i = 0; i < 8; i++) + { + TCHAR ch; + BYTE b = dw >> (32 - 4); + + if (b < 0x0A) + ch = b + TEXT('0'); + else + ch = b - 0x0A + TEXT('A'); + + szMutexName[mutexNameLen++] = ch; + dw <<= 4; + } + + szMutexName[mutexNameLen] = TEXT('\0'); + + return CreateMutex(NULL, FALSE, szMutexName); +} + +//------------------------------------------------------------------------- +MH_STATUS WINAPI MH_Initialize(VOID) +{ + if (g_hMutex != NULL) + return MH_ERROR_ALREADY_INITIALIZED; + + g_hMutex = CreateProcessMutex(); + if (g_hMutex == NULL) + return MH_ERROR_MUTEX_FAILURE; + + g_hHeap = HeapCreate(0, 0, 0); + if (g_hHeap == NULL) + { + CloseHandle(g_hMutex); + g_hMutex = NULL; + return MH_ERROR_MEMORY_ALLOC; + } + + // Initialize the internal function buffer. + InitializeBuffer(); + + return MH_OK; +} + +//------------------------------------------------------------------------- +MH_STATUS WINAPI MH_Uninitialize(VOID) +{ + if (g_hMutex == NULL) + return MH_ERROR_NOT_INITIALIZED; + + if (WaitForSingleObject(g_hMutex, INFINITE) != WAIT_OBJECT_0) + return MH_ERROR_MUTEX_FAILURE; + + MH_STATUS status = EnableAllHooksLL(FALSE); + + ReleaseMutex(g_hMutex); + + if (status != MH_OK) + return status; + + // Free the internal function buffer. + // HeapFree is actually not required, but some tools detect a false + // memory leak without HeapFree. + UninitializeBuffer(); + HeapFree(g_hHeap, 0, g_hooks.pItems); + HeapDestroy(g_hHeap); + g_hHeap = NULL; + + g_hooks.pItems = NULL; + g_hooks.capacity = 0; + g_hooks.size = 0; + + CloseHandle(g_hMutex); + g_hMutex = NULL; + + return MH_OK; +} + +//------------------------------------------------------------------------- +MH_STATUS WINAPI MH_SetThreadFreezeMethod(MH_THREAD_FREEZE_METHOD method) +{ + if (g_hMutex == NULL) + return MH_ERROR_NOT_INITIALIZED; + + if (WaitForSingleObject(g_hMutex, INFINITE) != WAIT_OBJECT_0) + return MH_ERROR_MUTEX_FAILURE; + + if (method == MH_FREEZE_METHOD_FAST_UNDOCUMENTED && !NtGetNextThread) + { + HMODULE hNtdll = GetModuleHandle(L"ntdll.dll"); + if (hNtdll) + NtGetNextThread = (NtGetNextThread_t)GetProcAddress(hNtdll, "NtGetNextThread"); + + if (!NtGetNextThread) + { + // Fall back to the original method. + method = MH_FREEZE_METHOD_ORIGINAL; + } + } + + g_threadFreezeMethod = method; + + ReleaseMutex(g_hMutex); + + return MH_OK; +} + +//------------------------------------------------------------------------- +MH_STATUS WINAPI MH_CreateHookEx(ULONG_PTR hookIdent, LPVOID pTarget, LPVOID pDetour, LPVOID *ppOriginal) +{ + if (g_hMutex == NULL) + return MH_ERROR_NOT_INITIALIZED; + + if (WaitForSingleObject(g_hMutex, INFINITE) != WAIT_OBJECT_0) + return MH_ERROR_MUTEX_FAILURE; + + MH_STATUS status = MH_OK; + + if (IsExecutableAddress(pTarget) && IsExecutableAddress(pDetour)) + { + UINT pos = FindHookEntry(hookIdent, pTarget); + if (pos == INVALID_HOOK_POS) + { + PEXEC_BUFFER pBuffer = AllocateBuffer(pTarget); + if (pBuffer != NULL) + { + PHOOK_ENTRY pHook = AddHookEntry(); + if (pHook != NULL) + { + pBuffer->hookIdent = hookIdent; + pBuffer->pDisableHookChain = DisableHookChain; + CreateRelayFunction(&pBuffer->jmpRelay, pDetour); + + pHook->hookIdent = hookIdent; + pHook->pTarget = pTarget; + pHook->pDetour = pDetour; + pHook->pExecBuffer = pBuffer; + pHook->isEnabled = FALSE; + pHook->queueEnable = FALSE; + + if (ppOriginal != NULL) + *ppOriginal = pBuffer->trampoline; + } + else + { + status = MH_ERROR_MEMORY_ALLOC; + } + + if (status != MH_OK) + { + FreeBuffer(pBuffer); + } + } + else + { + status = MH_ERROR_MEMORY_ALLOC; + } + } + else + { + status = MH_ERROR_ALREADY_CREATED; + } + } + else + { + status = MH_ERROR_NOT_EXECUTABLE; + } + + ReleaseMutex(g_hMutex); + + return status; +} + +//------------------------------------------------------------------------- +MH_STATUS WINAPI MH_CreateHook(LPVOID pTarget, LPVOID pDetour, LPVOID* ppOriginal) +{ + return MH_CreateHookEx(0, pTarget, pDetour, ppOriginal); +} + +//------------------------------------------------------------------------- +MH_STATUS WINAPI MH_RemoveHookEx(ULONG_PTR hookIdent, LPVOID pTarget) +{ + if (g_hMutex == NULL) + return MH_ERROR_NOT_INITIALIZED; + + if (WaitForSingleObject(g_hMutex, INFINITE) != WAIT_OBJECT_0) + return MH_ERROR_MUTEX_FAILURE; + + MH_STATUS status = MH_OK; + + if (pTarget == MH_ALL_HOOKS) + { + status = EnableHooksLL(FALSE, hookIdent, FALSE); + if (status == MH_OK) + { + UINT i = 0; + while (i < g_hooks.size) + { + PHOOK_ENTRY pHook = &g_hooks.pItems[i]; + if (pHook->hookIdent == hookIdent) + { + FreeBuffer(pHook->pExecBuffer); + DeleteHookEntry(i); + } + else + { + ++i; + } + } + } + } + else + { + UINT pos = FindHookEntry(hookIdent, pTarget); + if (pos != INVALID_HOOK_POS) + { + if (g_hooks.pItems[pos].isEnabled) + { + FROZEN_THREADS threads; + status = Freeze(&threads); + if (status == MH_OK) + { + status = EnableHookLL(pos, FALSE, &threads); + + Unfreeze(&threads); + } + } + + if (status == MH_OK) + { + FreeBuffer(g_hooks.pItems[pos].pExecBuffer); + DeleteHookEntry(pos); + } + } + else + { + status = MH_ERROR_NOT_CREATED; + } + } + + ReleaseMutex(g_hMutex); + + return status; +} + +//------------------------------------------------------------------------- +MH_STATUS WINAPI MH_RemoveHook(LPVOID pTarget) +{ + return MH_RemoveHookEx(0, pTarget); +} + +//------------------------------------------------------------------------- +static MH_STATUS WINAPI DisableHookChain(ULONG_PTR hookIdent, LPVOID pTarget, UINT parentPos, ENABLE_HOOK_LL_PROC ParentEnableHookLL, PFROZEN_THREADS pThreads) +{ + MH_STATUS status; + + UINT pos = FindHookEntry(hookIdent, pTarget); + if (pos == INVALID_HOOK_POS) + return MH_ERROR_NOT_CREATED; + + if (!g_hooks.pItems[pos].isEnabled) + return MH_ERROR_DISABLED; + + // We're not Freeze()-ing the threads here, because we assume that the function + // was called from a different MinHook module, which already suspended all threads. + + status = EnableHookLL(pos, FALSE, pThreads); + if (status != MH_OK) + return status; + + status = ParentEnableHookLL(parentPos, FALSE, pThreads); + if (status != MH_OK) + return status; + + return EnableHookLL(pos, TRUE, pThreads); +} + +//------------------------------------------------------------------------- +static MH_STATUS EnableHook(ULONG_PTR hookIdent, LPVOID pTarget, BOOL enable) +{ + if (g_hMutex == NULL) + return MH_ERROR_NOT_INITIALIZED; + + if (WaitForSingleObject(g_hMutex, INFINITE) != WAIT_OBJECT_0) + return MH_ERROR_MUTEX_FAILURE; + + MH_STATUS status = MH_OK; + + if (pTarget == MH_ALL_HOOKS) + { + status = EnableHooksLL(FALSE, hookIdent, enable); + } + else + { + UINT pos = FindHookEntry(hookIdent, pTarget); + if (pos != INVALID_HOOK_POS) + { + if (g_hooks.pItems[pos].isEnabled != enable) + { + FROZEN_THREADS threads; + status = Freeze(&threads); + if (status == MH_OK) + { + status = EnableHookLL(pos, enable, &threads); + + Unfreeze(&threads); + } + } + else + { + status = enable ? MH_ERROR_ENABLED : MH_ERROR_DISABLED; + } + } + else + { + status = MH_ERROR_NOT_CREATED; + } + } + + ReleaseMutex(g_hMutex); + + return status; +} + +//------------------------------------------------------------------------- +MH_STATUS WINAPI MH_EnableHookEx(ULONG_PTR hookIdent, LPVOID pTarget) +{ + return EnableHook(hookIdent, pTarget, TRUE); +} + +//------------------------------------------------------------------------- +MH_STATUS WINAPI MH_EnableHook(LPVOID pTarget) +{ + return MH_EnableHookEx(0, pTarget); +} + +//------------------------------------------------------------------------- +MH_STATUS WINAPI MH_DisableHookEx(ULONG_PTR hookIdent, LPVOID pTarget) +{ + return EnableHook(hookIdent, pTarget, FALSE); +} + +//------------------------------------------------------------------------- +MH_STATUS WINAPI MH_DisableHook(LPVOID pTarget) +{ + return MH_DisableHookEx(0, pTarget); +} + +//------------------------------------------------------------------------- +static MH_STATUS QueueHook(ULONG_PTR hookIdent, LPVOID pTarget, BOOL queueEnable) +{ + if (g_hMutex == NULL) + return MH_ERROR_NOT_INITIALIZED; + + if (WaitForSingleObject(g_hMutex, INFINITE) != WAIT_OBJECT_0) + return MH_ERROR_MUTEX_FAILURE; + + MH_STATUS status = MH_OK; + + if (pTarget == MH_ALL_HOOKS) + { + UINT i; + for (i = 0; i < g_hooks.size; ++i) + { + PHOOK_ENTRY pHook = &g_hooks.pItems[i]; + if (pHook->hookIdent == hookIdent) + pHook->queueEnable = queueEnable; + } + } + else + { + UINT pos = FindHookEntry(hookIdent, pTarget); + if (pos != INVALID_HOOK_POS) + { + g_hooks.pItems[pos].queueEnable = queueEnable; + } + else + { + status = MH_ERROR_NOT_CREATED; + } + } + + ReleaseMutex(g_hMutex); + + return status; +} + +//------------------------------------------------------------------------- +MH_STATUS WINAPI MH_QueueEnableHookEx(ULONG_PTR hookIdent, LPVOID pTarget) +{ + return QueueHook(hookIdent, pTarget, TRUE); +} + +//------------------------------------------------------------------------- +MH_STATUS WINAPI MH_QueueEnableHook(LPVOID pTarget) +{ + return MH_QueueEnableHookEx(0, pTarget); +} + +//------------------------------------------------------------------------- +MH_STATUS WINAPI MH_QueueDisableHookEx(ULONG_PTR hookIdent, LPVOID pTarget) +{ + return QueueHook(hookIdent, pTarget, FALSE); +} + +//------------------------------------------------------------------------- +MH_STATUS WINAPI MH_QueueDisableHook(LPVOID pTarget) +{ + return MH_QueueDisableHookEx(0, pTarget); +} + +//------------------------------------------------------------------------- +MH_STATUS WINAPI MH_ApplyQueued(VOID) +{ + if (g_hMutex == NULL) + return MH_ERROR_NOT_INITIALIZED; + + if (WaitForSingleObject(g_hMutex, INFINITE) != WAIT_OBJECT_0) + return MH_ERROR_MUTEX_FAILURE; + + MH_STATUS status = MH_OK; + UINT i, first = INVALID_HOOK_POS; + + for (i = 0; i < g_hooks.size; ++i) + { + if (g_hooks.pItems[i].isEnabled != g_hooks.pItems[i].queueEnable) + { + first = i; + break; + } + } + + if (first != INVALID_HOOK_POS) + { + FROZEN_THREADS threads; + status = Freeze(&threads); + if (status == MH_OK) + { + for (i = first; i < g_hooks.size; ++i) + { + PHOOK_ENTRY pHook = &g_hooks.pItems[i]; + if (pHook->isEnabled != pHook->queueEnable) + { + MH_STATUS enable_status = EnableHookLL(i, pHook->queueEnable, &threads); + + // Instead of stopping on the first error, we apply as much + // hooks as we can, and return the last error, if any. + if (enable_status != MH_OK) + status = enable_status; + } + } + + Unfreeze(&threads); + } + } + + ReleaseMutex(g_hMutex); + + return status; +} + +//------------------------------------------------------------------------- +MH_STATUS WINAPI MH_CreateHookApiEx( + LPCWSTR pszModule, LPCSTR pszProcName, LPVOID pDetour, + LPVOID *ppOriginal, LPVOID *ppTarget) +{ + HMODULE hModule; + LPVOID pTarget; + + hModule = GetModuleHandleW(pszModule); + if (hModule == NULL) + return MH_ERROR_MODULE_NOT_FOUND; + + pTarget = (LPVOID)GetProcAddress(hModule, pszProcName); + if (pTarget == NULL) + return MH_ERROR_FUNCTION_NOT_FOUND; + + if(ppTarget != NULL) + *ppTarget = pTarget; + + return MH_CreateHook(pTarget, pDetour, ppOriginal); +} + +//------------------------------------------------------------------------- +MH_STATUS WINAPI MH_CreateHookApi( + LPCWSTR pszModule, LPCSTR pszProcName, LPVOID pDetour, LPVOID *ppOriginal) +{ + return MH_CreateHookApiEx(pszModule, pszProcName, pDetour, ppOriginal, NULL); +} + +//------------------------------------------------------------------------- +const char * WINAPI MH_StatusToString(MH_STATUS status) +{ +#define MH_ST2STR(x) \ + case x: \ + return #x; + + switch (status) { + MH_ST2STR(MH_UNKNOWN) + MH_ST2STR(MH_OK) + MH_ST2STR(MH_ERROR_ALREADY_INITIALIZED) + MH_ST2STR(MH_ERROR_NOT_INITIALIZED) + MH_ST2STR(MH_ERROR_ALREADY_CREATED) + MH_ST2STR(MH_ERROR_NOT_CREATED) + MH_ST2STR(MH_ERROR_ENABLED) + MH_ST2STR(MH_ERROR_DISABLED) + MH_ST2STR(MH_ERROR_NOT_EXECUTABLE) + MH_ST2STR(MH_ERROR_UNSUPPORTED_FUNCTION) + MH_ST2STR(MH_ERROR_MEMORY_ALLOC) + MH_ST2STR(MH_ERROR_MEMORY_PROTECT) + MH_ST2STR(MH_ERROR_MODULE_NOT_FOUND) + MH_ST2STR(MH_ERROR_FUNCTION_NOT_FOUND) + MH_ST2STR(MH_ERROR_MUTEX_FAILURE) + } + +#undef MH_ST2STR + + return "(unknown)"; +} diff --git a/galliumhook/minhook-multihook/src/trampoline.c b/galliumhook/minhook-multihook/src/trampoline.c new file mode 100644 index 0000000..4a4dc83 --- /dev/null +++ b/galliumhook/minhook-multihook/src/trampoline.c @@ -0,0 +1,327 @@ +/* + * MinHook - The Minimalistic API Hooking Library for x64/x86 + * Copyright (C) 2009-2017 Tsuda Kageyu. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#ifdef _MSC_VER + #include +#endif + +#ifndef ARRAYSIZE + #define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0])) +#endif + +#if defined(_M_X64) || defined(__x86_64__) + #include "./hde/hde64.h" + typedef hde64s HDE; + #define HDE_DISASM(code, hs) hde64_disasm(code, hs) +#else + #include "./hde/hde32.h" + typedef hde32s HDE; + #define HDE_DISASM(code, hs) hde32_disasm(code, hs) +#endif + +#include "trampoline.h" +#include "buffer.h" + +//------------------------------------------------------------------------- +static BOOL IsCodePadding(LPBYTE pInst, UINT size) +{ + UINT i; + + if (pInst[0] != 0x00 && pInst[0] != 0x90 && pInst[0] != 0xCC) + return FALSE; + + for (i = 1; i < size; ++i) + { + if (pInst[i] != pInst[0]) + return FALSE; + } + return TRUE; +} + +//------------------------------------------------------------------------- +VOID CreateRelayFunction(PJMP_RELAY pJmpRelay, LPVOID pDetour) +{ +#if defined(_M_X64) || defined(__x86_64__) + JMP_ABS jmp = { + 0xFF, 0x25, 0x00000000, // FF25 00000000: JMP [RIP+6] + 0x0000000000000000ULL // Absolute destination address + }; + + jmp.address = (ULONG_PTR)pDetour; +#else + JMP_REL jmp = { + 0xE9, // E9 xxxxxxxx: JMP +5+xxxxxxxx + 0x00000000 // Relative destination address + }; + + jmp.operand = (UINT32)((LPBYTE)pDetour - ((LPBYTE)pJmpRelay + sizeof(jmp))); +#endif + + memcpy(pJmpRelay, &jmp, sizeof(jmp)); +} + +//------------------------------------------------------------------------- +BOOL CreateTrampolineFunction(PTRAMPOLINE ct) +{ +#if defined(_M_X64) || defined(__x86_64__) + CALL_ABS call = { + 0xFF, 0x15, 0x00000002, // FF15 00000002: CALL [RIP+8] + 0xEB, 0x08, // EB 08: JMP +10 + 0x0000000000000000ULL // Absolute destination address + }; + JMP_ABS jmp = { + 0xFF, 0x25, 0x00000000, // FF25 00000000: JMP [RIP+6] + 0x0000000000000000ULL // Absolute destination address + }; + JCC_ABS jcc = { + 0x70, 0x0E, // 7* 0E: J** +16 + 0xFF, 0x25, 0x00000000, // FF25 00000000: JMP [RIP+6] + 0x0000000000000000ULL // Absolute destination address + }; +#else + CALL_REL call = { + 0xE8, // E8 xxxxxxxx: CALL +5+xxxxxxxx + 0x00000000 // Relative destination address + }; + JMP_REL jmp = { + 0xE9, // E9 xxxxxxxx: JMP +5+xxxxxxxx + 0x00000000 // Relative destination address + }; + JCC_REL jcc = { + 0x0F, 0x80, // 0F8* xxxxxxxx: J** +6+xxxxxxxx + 0x00000000 // Relative destination address + }; +#endif + + UINT8 oldPos = 0; + UINT8 newPos = 0; + ULONG_PTR jmpDest = 0; // Destination address of an internal jump. + BOOL finished = FALSE; // Is the function completed? +#if defined(_M_X64) || defined(__x86_64__) + UINT8 instBuf[16]; +#endif + + ct->patchAbove = FALSE; + ct->nIP = 0; + + do + { + HDE hs; + UINT copySize; + LPVOID pCopySrc; + ULONG_PTR pOldInst = (ULONG_PTR)ct->pTarget + oldPos; + ULONG_PTR pNewInst = (ULONG_PTR)ct->pTrampoline + newPos; + + copySize = HDE_DISASM((LPVOID)pOldInst, &hs); + if (hs.flags & F_ERROR) + return FALSE; + + pCopySrc = (LPVOID)pOldInst; + if (oldPos >= sizeof(JMP_REL)) + { + // The trampoline function is long enough. + // Complete the function with the jump to the target function. +#if defined(_M_X64) || defined(__x86_64__) + jmp.address = pOldInst; +#else + jmp.operand = (UINT32)(pOldInst - (pNewInst + sizeof(jmp))); +#endif + pCopySrc = &jmp; + copySize = sizeof(jmp); + + finished = TRUE; + } +#if defined(_M_X64) || defined(__x86_64__) + else if ((hs.modrm & 0xC7) == 0x05) + { + // Instructions using RIP relative addressing. (ModR/M = 00???101B) + + // Modify the RIP relative address. + PUINT32 pRelAddr; + + // Avoid using memcpy to reduce the footprint. +#ifndef _MSC_VER + memcpy(instBuf, (LPBYTE)pOldInst, copySize); +#else + __movsb(instBuf, (LPBYTE)pOldInst, copySize); +#endif + pCopySrc = instBuf; + + // Relative address is stored at (instruction length - immediate value length - 4). + pRelAddr = (PUINT32)(instBuf + hs.len - ((hs.flags & 0x3C) >> 2) - 4); + *pRelAddr + = (UINT32)((pOldInst + hs.len + (INT32)hs.disp.disp32) - (pNewInst + hs.len)); + + // Complete the function if JMP (FF /4). + if (hs.opcode == 0xFF && hs.modrm_reg == 4) + finished = TRUE; + } +#endif + else if (hs.opcode == 0xE8) + { + // Direct relative CALL + ULONG_PTR dest = pOldInst + hs.len + (INT32)hs.imm.imm32; +#if defined(_M_X64) || defined(__x86_64__) + call.address = dest; +#else + call.operand = (UINT32)(dest - (pNewInst + sizeof(call))); +#endif + pCopySrc = &call; + copySize = sizeof(call); + } + else if ((hs.opcode & 0xFD) == 0xE9) + { + // Direct relative JMP (EB or E9) + ULONG_PTR dest = pOldInst + hs.len; + + if (hs.opcode == 0xEB) // isShort jmp + dest += (INT8)hs.imm.imm8; + else + dest += (INT32)hs.imm.imm32; + + // Simply copy an internal jump. + if ((ULONG_PTR)ct->pTarget <= dest + && dest < ((ULONG_PTR)ct->pTarget + sizeof(JMP_REL))) + { + if (jmpDest < dest) + jmpDest = dest; + } + else + { +#if defined(_M_X64) || defined(__x86_64__) + jmp.address = dest; +#else + jmp.operand = (UINT32)(dest - (pNewInst + sizeof(jmp))); +#endif + pCopySrc = &jmp; + copySize = sizeof(jmp); + + // Exit the function if it is not in the branch. + finished = (pOldInst >= jmpDest); + } + } + else if ((hs.opcode & 0xF0) == 0x70 + || (hs.opcode & 0xFC) == 0xE0 + || (hs.opcode2 & 0xF0) == 0x80) + { + // Direct relative Jcc + ULONG_PTR dest = pOldInst + hs.len; + + if ((hs.opcode & 0xF0) == 0x70 // Jcc + || (hs.opcode & 0xFC) == 0xE0) // LOOPNZ/LOOPZ/LOOP/JECXZ + dest += (INT8)hs.imm.imm8; + else + dest += (INT32)hs.imm.imm32; + + // Simply copy an internal jump. + if ((ULONG_PTR)ct->pTarget <= dest + && dest < ((ULONG_PTR)ct->pTarget + sizeof(JMP_REL))) + { + if (jmpDest < dest) + jmpDest = dest; + } + else if ((hs.opcode & 0xFC) == 0xE0) + { + // LOOPNZ/LOOPZ/LOOP/JCXZ/JECXZ to the outside are not supported. + return FALSE; + } + else + { + UINT8 cond = ((hs.opcode != 0x0F ? hs.opcode : hs.opcode2) & 0x0F); +#if defined(_M_X64) || defined(__x86_64__) + // Invert the condition in x64 mode to simplify the conditional jump logic. + jcc.opcode = 0x71 ^ cond; + jcc.address = dest; +#else + jcc.opcode1 = 0x80 | cond; + jcc.operand = (UINT32)(dest - (pNewInst + sizeof(jcc))); +#endif + pCopySrc = &jcc; + copySize = sizeof(jcc); + } + } + else if ((hs.opcode & 0xFE) == 0xC2) + { + // RET (C2 or C3) + + // Complete the function if not in a branch. + finished = (pOldInst >= jmpDest); + } + + // Can't alter the instruction length in a branch. + if (pOldInst < jmpDest && copySize != hs.len) + return FALSE; + + // Trampoline function is too large. + if ((newPos + copySize) > ct->trampolineSize) + return FALSE; + + // Trampoline function has too many instructions. + if (ct->nIP >= ARRAYSIZE(ct->oldIPs)) + return FALSE; + + ct->oldIPs[ct->nIP] = oldPos; + ct->newIPs[ct->nIP] = newPos; + ct->nIP++; + + // Avoid using memcpy to reduce the footprint. +#ifndef _MSC_VER + memcpy((LPBYTE)ct->pTrampoline + newPos, pCopySrc, copySize); +#else + __movsb((LPBYTE)ct->pTrampoline + newPos, (LPBYTE)pCopySrc, copySize); +#endif + newPos += copySize; + oldPos += hs.len; + } + while (!finished); + + // Is there enough place for a long jump? + if (oldPos < sizeof(JMP_REL) + && !IsCodePadding((LPBYTE)ct->pTarget + oldPos, sizeof(JMP_REL) - oldPos)) + { + // Is there enough place for a short jump? + if (oldPos < sizeof(JMP_REL_SHORT) + && !IsCodePadding((LPBYTE)ct->pTarget + oldPos, sizeof(JMP_REL_SHORT) - oldPos)) + { + return FALSE; + } + + // Can we place the long jump above the function? + if (!IsExecutableAddress((LPBYTE)ct->pTarget - sizeof(JMP_REL))) + return FALSE; + + if (!IsCodePadding((LPBYTE)ct->pTarget - sizeof(JMP_REL), sizeof(JMP_REL))) + return FALSE; + + ct->patchAbove = TRUE; + } + + return TRUE; +} diff --git a/galliumhook/minhook-multihook/src/trampoline.h b/galliumhook/minhook-multihook/src/trampoline.h new file mode 100644 index 0000000..1ef3a1e --- /dev/null +++ b/galliumhook/minhook-multihook/src/trampoline.h @@ -0,0 +1,111 @@ +/* + * MinHook - The Minimalistic API Hooking Library for x64/x86 + * Copyright (C) 2009-2017 Tsuda Kageyu. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#pragma pack(push, 1) + +// Structs for writing x86/x64 instructions. + +// 8-bit relative jump. +typedef struct _JMP_REL_SHORT +{ + UINT8 opcode; // EB xx: JMP +2+xx + UINT8 operand; // Relative destination address +} JMP_REL_SHORT, *PJMP_REL_SHORT; + +// 32-bit direct relative jump/call. +typedef struct _JMP_REL +{ + UINT8 opcode; // E9/E8 xxxxxxxx: JMP/CALL +5+xxxxxxxx + UINT32 operand; // Relative destination address +} JMP_REL, *PJMP_REL, CALL_REL; + +// 64-bit indirect absolute jump. +typedef struct _JMP_ABS +{ + UINT8 opcode0; // FF25 00000000: JMP [+6] + UINT8 opcode1; + UINT32 dummy; + UINT64 address; // Absolute destination address +} JMP_ABS, *PJMP_ABS; + +// 64-bit indirect absolute call. +typedef struct _CALL_ABS +{ + UINT8 opcode0; // FF15 00000002: CALL [+6] + UINT8 opcode1; + UINT32 dummy0; + UINT8 dummy1; // EB 08: JMP +10 + UINT8 dummy2; + UINT64 address; // Absolute destination address +} CALL_ABS; + +// 32-bit direct relative conditional jumps. +typedef struct _JCC_REL +{ + UINT8 opcode0; // 0F8* xxxxxxxx: J** +6+xxxxxxxx + UINT8 opcode1; + UINT32 operand; // Relative destination address +} JCC_REL; + +// 64bit indirect absolute conditional jumps that x64 lacks. +typedef struct _JCC_ABS +{ + UINT8 opcode; // 7* 0E: J** +16 + UINT8 dummy0; + UINT8 dummy1; // FF25 00000000: JMP [+6] + UINT8 dummy2; + UINT32 dummy3; + UINT64 address; // Absolute destination address +} JCC_ABS; + +#pragma pack(pop) + +#if defined(_M_X64) || defined(__x86_64__) + typedef JMP_ABS JMP_RELAY; + typedef PJMP_ABS PJMP_RELAY; +#else + typedef JMP_REL JMP_RELAY; + typedef PJMP_REL PJMP_RELAY; +#endif + +typedef struct _TRAMPOLINE +{ + LPVOID pTarget; // [In] Address of the target function. + LPVOID pTrampoline; // [In] Buffer address for the trampoline function. + UINT trampolineSize; // [In] The size of the trampoline function buffer. + + BOOL patchAbove; // [Out] Should use the hot patch area? + UINT nIP; // [Out] Number of the instruction boundaries. + UINT8 oldIPs[8]; // [Out] Instruction boundaries of the target function. + UINT8 newIPs[8]; // [Out] Instruction boundaries of the trampoline function. +} TRAMPOLINE, *PTRAMPOLINE; + +VOID CreateRelayFunction(PJMP_RELAY pJmpRelay, LPVOID pDetour); +BOOL CreateTrampolineFunction(PTRAMPOLINE ct);