From d23c7d4e0234f20278a892e4e6b3b036170eb9b5 Mon Sep 17 00:00:00 2001 From: Eliot Date: Mon, 25 Mar 2024 04:23:22 +0100 Subject: [PATCH 1/4] Revert "Deprecate all ObjectNode implementations. (These will be re-implemented in UE-Explorer instead)." This reverts commit 6aa6a718708e06b567eb8dfa5e9acffe019c8b28. --- CHANGELOG.md | 55 +++++- src/Core/Classes/Props/UPropertyDecompiler.cs | 4 +- src/Core/Classes/UClassNode.cs | 42 +++++ src/Core/Classes/UFieldNode.cs | 17 ++ src/Core/Classes/UFunctionNode.cs | 65 +++++++ src/Core/Classes/UObjectNode.cs | 134 +++++++++++++++ src/Core/Classes/UPackageNode.cs | 12 ++ src/Core/Classes/UPropertyNode.cs | 47 ++++++ src/Core/Classes/UStateNode.cs | 29 ++++ src/Core/Classes/UStructNode.cs | 76 +++++++++ src/ObjectNodes.cs | 81 +++++++++ src/UnrealInterfaces.cs | 11 ++ src/UnrealMethods.cs | 158 ++++++++++++++++-- 13 files changed, 717 insertions(+), 14 deletions(-) create mode 100644 src/Core/Classes/UClassNode.cs create mode 100644 src/Core/Classes/UFieldNode.cs create mode 100644 src/Core/Classes/UFunctionNode.cs create mode 100644 src/Core/Classes/UObjectNode.cs create mode 100644 src/Core/Classes/UPackageNode.cs create mode 100644 src/Core/Classes/UPropertyNode.cs create mode 100644 src/Core/Classes/UStateNode.cs create mode 100644 src/Core/Classes/UStructNode.cs create mode 100644 src/ObjectNodes.cs diff --git a/CHANGELOG.md b/CHANGELOG.md index 1893b893..e68f3a0b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,13 +1,62 @@ +# [1.4.0](https://github.com/EliotVU/Unreal-Library/releases/tag/1.4.0) + +Notable changes that affect UnrealScript output: + +* Improved decompilation output of string and decimal literals. +* 5141285c Improved decompilation of delegate assignments (in a T3D context) +* 6d889c87 Added decompilation of optional parameter assignments e.g. `function MyFunction(option bool A = true);`. +* e55cfce0 Fixed decompilation with arrays of bools + +Notable changes that affect support of games: + +General deserialization fixes that affect all of UE1, UE2, and UE3 builds, as well as more specifically: + +* 13460cca Support for Battleborn +* 4aff61fa Support for Duke Nukem Forever (2011) +* bce38c4f Support for Tom Clancy's Splinter Cell +* 809edaad Support for Harry Potter (UE1) data class {USound} +* b3e1489d Support for Devastation (UE2, 2003) +* 4780771a Support for Clive Barker's Undying (UE1) data classes {UClass, UTextBuffer, UPalette, USound} +* 01772a83 Support for Lemony Snicket's A Series of Unfortunate Events data class {UProperty} +* c4c1978d Fixed support for Dungeon Defenders 2 (versions 687-688/111-117) +* 86538e5d Fixed support for Vanguard: Saga of Heroes +* eb82dba5 Fixed support for Rocket League (version 868/003) +* 6ed6ed74 Fixed support for Hawken (version 860/002) +* b4b79773 Fixed ResizeStringToken for UE1 builds +* 3653f8e1 Fixed ReturnToken and BeginFunctionToken for UE1 builds (with a package version of 61) +* 9a659549 Fixed deserialization of Heritages for UE1 builds (with a package version older than 68) + +Notable changes that affect various data structures: + +* Improved detection of UComponent objects and class types. +* ea3c1aa5 Support for UE4 .uasset packages (earlier builds only) +* e37b8a12 Support for class {UTexture}, f1b74af1 {UPrimitive, UTexture2D and its derivatives} (UE3) +* aa5ca861 Support for classes: {UFont, UMultiFont} +* ab290b6c Support for types {UPolys, FPoly} +* 02bea77b Support for types {FUntypedBulkData} (UE3) and {TLazyArray} (UE1, UE2) +* 94e02927 Support for structures: {FPointRegion, FCoords, FPlane, FScale, FSphere, FRotator, FVector, FGuid, FBox, FLinearColor, FMatrix, FQuat, FRange, FRangeVector, FVector2D, FVector4} +* 09c76240 Support for class {USoundGroup} (UE2.5) + +**Support for the data types listed above have only been implemented for the standard structure that Epic Games uses** + # [1.3.1](https://github.com/EliotVU/Unreal-Library/releases/tag/1.3.1) +Notable changes back-ported from 'develop' version 1.4.0: + +* Added support for various data structures: FColor; and data class UBitmapMaterial (UE2) + * Improved support for Batman series * Improved support for Transformers series -* Fixed the decompilation of UnrealScript casting byte-codes that were swapped i.e. `InterfaceToBool` with `InterfaceToObject`. -* Fixed a missing package version check in UStateFrame (this affected some object classes that are usually found in map package files). -* Added the capability to override the interpreted version for packages of builds that are auto-detected. +* e8308284 Fixed decompilation of primitive castings for UE1 builds +* ffaca763 Fixed decompilation of interface castings i.e. `InterfaceToBool` with `InterfaceToObject` (UE3). +* 3317e06a Fixed a missing package version check in UStateFrame (this affected some object classes that are usually found in map package files). + +* 42783b16 Added the capability to override the interpreted version for packages of builds that are auto-detected. # [1.3.0](https://github.com/EliotVU/Unreal-Library/releases/tag/1.3.0.0) +Notable changes: + * Support for Vengeance which includes BioShock 1 & 2, Swat4, and Tribes: Vengeance * Support for Batman series (to the release branch, incomplete) * Support for Thief: Deadly Shadows and Deus Ex: Invisible War diff --git a/src/Core/Classes/Props/UPropertyDecompiler.cs b/src/Core/Classes/Props/UPropertyDecompiler.cs index 1512d92f..4e14c173 100644 --- a/src/Core/Classes/Props/UPropertyDecompiler.cs +++ b/src/Core/Classes/Props/UPropertyDecompiler.cs @@ -505,7 +505,9 @@ public string FormatFlags() return string.Empty; } - return output; + // alright... + //return "/*" + UnrealMethods.FlagToString( PropertyFlags ) + "*/ " + output; + return copyFlags != 0 ? "/*" + UnrealMethods.FlagToString(copyFlags) + "*/ " + output : output; } } } diff --git a/src/Core/Classes/UClassNode.cs b/src/Core/Classes/UClassNode.cs new file mode 100644 index 00000000..5df25a36 --- /dev/null +++ b/src/Core/Classes/UClassNode.cs @@ -0,0 +1,42 @@ +#if Forms +using System.Windows.Forms; + +namespace UELib.Core +{ + public partial class UClass + { + protected override void InitNodes(TreeNode node) + { + _ParentNode = AddSectionNode(node, nameof(UClass)); + AddSimpleObjectNode(_ParentNode, Within, "Within", Within != null ? Within.GetImageName() : ""); + + var classFlagsNode = AddTextNode(_ParentNode, $"Class Flags:{UnrealMethods.FlagToString(ClassFlags)}"); + classFlagsNode.ToolTipText = UnrealMethods.FlagsListToString( + UnrealMethods.FlagsToList(typeof(Flags.ClassFlags), ClassFlags) + ); + + base.InitNodes(_ParentNode); + } + + protected override void AddChildren(TreeNode node) + { + base.AddChildren(node); + AddObjectListNode(node, "States", States, nameof(UState)); + } + + public override string GetImageName() + { + if (IsClassInterface()) + { + return "Interface"; + } + if (IsClassWithin()) + { + return "UClass-Within"; + } + + return base.GetImageName(); + } + } +} +#endif \ No newline at end of file diff --git a/src/Core/Classes/UFieldNode.cs b/src/Core/Classes/UFieldNode.cs new file mode 100644 index 00000000..16672d3d --- /dev/null +++ b/src/Core/Classes/UFieldNode.cs @@ -0,0 +1,17 @@ +#if Forms +using System.Windows.Forms; + +namespace UELib.Core +{ + public partial class UField + { + protected override void InitNodes(TreeNode node) + { + _ParentNode = AddSectionNode(node, nameof(UField)); + AddSimpleObjectNode(_ParentNode, Super, "SuperField", Super != null ? Super.GetImageName() : ""); + AddSimpleObjectNode(_ParentNode, NextField, "NextField", NextField != null ? NextField.GetImageName() : ""); + base.InitNodes(_ParentNode); + } + } +} +#endif \ No newline at end of file diff --git a/src/Core/Classes/UFunctionNode.cs b/src/Core/Classes/UFunctionNode.cs new file mode 100644 index 00000000..7f3efa48 --- /dev/null +++ b/src/Core/Classes/UFunctionNode.cs @@ -0,0 +1,65 @@ +#if Forms +using System.Windows.Forms; + +namespace UELib.Core +{ + public partial class UFunction + { + protected override void InitNodes(TreeNode node) + { + node.ToolTipText = FormatHeader(); + _ParentNode = AddSectionNode(node, nameof(UFunction)); + + var funcFlagsNode = AddTextNode(_ParentNode, $"FunctionFlags:{UnrealMethods.FlagToString(FunctionFlags)}"); + funcFlagsNode.ToolTipText = + UnrealMethods.FlagsListToString(UnrealMethods.FlagsToList(typeof(Flags.FunctionFlags), FunctionFlags)); + + if (RepOffset > 0) + { + AddTextNode(_ParentNode, $"Replication Offset:{RepOffset}"); + } + + base.InitNodes(_ParentNode); + } + + protected override void AddChildren(TreeNode node) + { + base.AddChildren(node); + AddObjectListNode(node, "Parameters", Params, nameof(UProperty)); + AddObjectListNode(node, "Locals", Locals, nameof(UProperty)); + } + + public override string GetImageName() + { + var name = string.Empty; + if (HasFunctionFlag(Flags.FunctionFlags.Event)) + { + name = "Event"; + } + else if (HasFunctionFlag(Flags.FunctionFlags.Delegate)) + { + name = "Delegate"; + } + else if (HasFunctionFlag(Flags.FunctionFlags.Operator)) + { + name = "Operator"; + } + + if (name != string.Empty) + { + if (IsProtected()) + { + return $"{name}-Protected"; + } + if (IsPrivate()) + { + return $"{name}-Private"; + } + return name; + } + + return base.GetImageName(); + } + } +} +#endif \ No newline at end of file diff --git a/src/Core/Classes/UObjectNode.cs b/src/Core/Classes/UObjectNode.cs new file mode 100644 index 00000000..d28cde71 --- /dev/null +++ b/src/Core/Classes/UObjectNode.cs @@ -0,0 +1,134 @@ +#if Forms +using System.Collections.Generic; +using System.Linq; +using System.Windows.Forms; + +namespace UELib.Core +{ + public partial class UObject + { + protected TreeNode _ParentNode; + public bool HasInitializedNodes; + + public void InitializeNodes(TreeNode node) + { + if (HasInitializedNodes) + return; + + node.ToolTipText = FormatHeader(); + InitNodes(node); + AddChildren(node); + PostAddChildren(node); + + node.ImageKey = GetImageName(); + node.SelectedImageKey = node.ImageKey; + HasInitializedNodes = true; + } + + public virtual string GetImageName() + { + return GetType().IsSubclassOf(typeof(UProperty)) + ? nameof(UProperty) + : this is UScriptStruct + ? nameof(UStruct) + : GetType().Name; + } + + protected virtual void InitNodes(TreeNode node) + { + _ParentNode = AddSectionNode(node, nameof(UObject)); + var flagNode = AddTextNode(_ParentNode, $"ObjectFlags:{UnrealMethods.FlagToString(_ObjectFlags)}"); + flagNode.ToolTipText = UnrealMethods.FlagsListToString( + UnrealMethods.FlagsToList(typeof(Flags.ObjectFlagsLO), typeof(Flags.ObjectFlagsHO), _ObjectFlags) + ); + + AddTextNode(_ParentNode, $"Size:{ExportTable.SerialSize}"); + AddTextNode(_ParentNode, $"Offset:{ExportTable.SerialOffset}"); + } + + protected virtual void AddChildren(TreeNode node) + { + } + + protected virtual void PostAddChildren(TreeNode node) + { + } + + protected static TreeNode AddSectionNode(TreeNode p, string n) + { + var nn = new TreeNode(n) { ImageKey = "Extend" }; + nn.SelectedImageKey = nn.ImageKey; + p.Nodes.Add(nn); + return nn; + } + + protected static TreeNode AddTextNode(TreeNode p, string n) + { + var nn = new TreeNode(n) { ImageKey = "Info" }; + nn.SelectedImageKey = nn.ImageKey; + p.Nodes.Add(nn); + return nn; + } + + protected static ObjectNode AddObjectNode(TreeNode parentNode, UObject unrealObject, string imageName = "") + { + if (unrealObject == null) + return null; + + var objN = new ObjectNode(unrealObject) { Text = unrealObject.Name }; + unrealObject.InitializeNodes(objN); + if (imageName != string.Empty) + { + objN.ImageKey = imageName; + objN.SelectedImageKey = imageName; + } + + if (unrealObject.DeserializationState.HasFlag(ObjectState.Errorlized)) + { + objN.ForeColor = System.Drawing.Color.Red; + } + + parentNode.Nodes.Add(objN); + return objN; + } + + protected static ObjectNode AddSimpleObjectNode(TreeNode parentNode, UObject unrealObject, string text, + string imageName = "") + { + if (unrealObject == null) + return null; + + var objN = new ObjectNode(unrealObject) { Text = $"{text}:{unrealObject.Name}" }; + if (imageName != string.Empty) + { + objN.ImageKey = imageName; + objN.SelectedImageKey = imageName; + } + + parentNode.Nodes.Add(objN); + return objN; + } + + protected static ObjectListNode AddObjectListNode + ( + TreeNode parentNode, + string title, + IList objects, + string imageName = "TreeView" + ) where T : UObject + { + if (objects == null || !objects.Any()) + return null; + + var listNode = new ObjectListNode(imageName) { Text = title }; + foreach (var obj in objects) + { + AddObjectNode(listNode, obj, obj.GetType().Name); + } + + parentNode.Nodes.Add(listNode); + return listNode; + } + } +} +#endif \ No newline at end of file diff --git a/src/Core/Classes/UPackageNode.cs b/src/Core/Classes/UPackageNode.cs new file mode 100644 index 00000000..5d471f2e --- /dev/null +++ b/src/Core/Classes/UPackageNode.cs @@ -0,0 +1,12 @@ +#if Forms +namespace UELib.Core +{ + public partial class UPackage + { + public override string GetImageName() + { + return "Library"; + } + } +} +#endif \ No newline at end of file diff --git a/src/Core/Classes/UPropertyNode.cs b/src/Core/Classes/UPropertyNode.cs new file mode 100644 index 00000000..7850ad64 --- /dev/null +++ b/src/Core/Classes/UPropertyNode.cs @@ -0,0 +1,47 @@ +#if Forms +using System.Windows.Forms; + +namespace UELib.Core +{ + public partial class UProperty + { + protected override void InitNodes(TreeNode node) + { + _ParentNode = AddSectionNode(node, nameof(UProperty)); + var propertyFlagsNode = AddTextNode(_ParentNode, + $"Property Flags:{UnrealMethods.FlagToString(PropertyFlags)}" + ); + propertyFlagsNode.ToolTipText = UnrealMethods.FlagsListToString(UnrealMethods.FlagsToList( + typeof(Flags.PropertyFlagsLO), + typeof(Flags.PropertyFlagsHO), PropertyFlags) + ); + + if (RepOffset > 0) + { + AddTextNode(_ParentNode, $"Replication Offset:{RepOffset}"); + } + + base.InitNodes(_ParentNode); + } + + public override string GetImageName() + { + if (HasPropertyFlag(Flags.PropertyFlagsLO.ReturnParm)) + { + return "ReturnValue"; + } + + string which = base.GetImageName(); + if (IsProtected()) + { + return $"{which}-Protected"; + } + if (IsPrivate()) + { + return $"{which}-Private"; + } + return which; + } + } +} +#endif \ No newline at end of file diff --git a/src/Core/Classes/UStateNode.cs b/src/Core/Classes/UStateNode.cs new file mode 100644 index 00000000..429fe249 --- /dev/null +++ b/src/Core/Classes/UStateNode.cs @@ -0,0 +1,29 @@ +#if Forms +using System.Windows.Forms; + +namespace UELib.Core +{ + public partial class UState + { + protected override void InitNodes(TreeNode node) + { + _ParentNode = AddSectionNode(node, nameof(UState)); + + if (GetType() == typeof(UState)) + { + var stateFlagsNode = AddTextNode(_ParentNode, $"State Flags:{UnrealMethods.FlagToString(_StateFlags)}"); + stateFlagsNode.ToolTipText = + UnrealMethods.FlagsListToString(UnrealMethods.FlagsToList(typeof(Flags.StateFlags), _StateFlags)); + } + + base.InitNodes(_ParentNode); + } + + protected override void AddChildren(TreeNode node) + { + base.AddChildren(node); + AddObjectListNode(node, "Functions", Functions, nameof(UFunction)); + } + } +} +#endif \ No newline at end of file diff --git a/src/Core/Classes/UStructNode.cs b/src/Core/Classes/UStructNode.cs new file mode 100644 index 00000000..70edf9e3 --- /dev/null +++ b/src/Core/Classes/UStructNode.cs @@ -0,0 +1,76 @@ +#if Forms +using System.Collections.Generic; +using System.Windows.Forms; + +namespace UELib.Core +{ + public partial class UStruct + { + protected override void InitNodes(TreeNode node) + { + _ParentNode = AddSectionNode(node, nameof(UStruct)); + if (IsPureStruct()) + { + var sFlagsNode = AddTextNode(_ParentNode, $"Struct Flags:{UnrealMethods.FlagToString(StructFlags)}"); + sFlagsNode.ToolTipText = + UnrealMethods.FlagsListToString(UnrealMethods.FlagsToList(typeof(Flags.StructFlags), StructFlags)); + } + + AddTextNode(_ParentNode, $"Script Size:{DataScriptSize}"); + base.InitNodes(_ParentNode); + } + + protected override void AddChildren(TreeNode node) + { + if (ScriptText != null) + { + AddObjectNode(node, ScriptText, nameof(UObject)); + } + + if (CppText != null) + { + AddObjectNode(node, CppText, nameof(UObject)); + } + + if (ProcessedText != null) + { + AddObjectNode(node, ProcessedText, nameof(UObject)); + } + + var children = new List(); + for (var child = Children; child != null; child = child.NextField) + { + children.Insert(0, child); + } + AddObjectListNode(node, "Children", children, nameof(UObject)); + AddObjectListNode(node, "Constants", Constants, nameof(UConst)); + AddObjectListNode(node, "Enumerations", Enums, nameof(UEnum)); + AddObjectListNode(node, "Structures", Structs, nameof(UStruct)); + // Not if the upper class is a function; UFunction adds locals and parameters instead + if (GetType() != typeof(UFunction)) + { + AddObjectListNode(node, "Variables", Variables, nameof(UProperty)); + } + } + + protected override void PostAddChildren(TreeNode node) + { + if (Properties == null || Properties.Count <= 0) + return; + + var defNode = new ObjectListNode + { + Text = "Default Values", + ImageKey = "UDefaultProperty", + SelectedImageKey = "UDefaultProperty" + }; + node.Nodes.Add(defNode); + foreach (var def in Properties) + { + var objN = new DefaultObjectNode(def) { Text = def.Name }; + defNode.Nodes.Add(objN); + } + } + } +} +#endif \ No newline at end of file diff --git a/src/ObjectNodes.cs b/src/ObjectNodes.cs new file mode 100644 index 00000000..15b82396 --- /dev/null +++ b/src/ObjectNodes.cs @@ -0,0 +1,81 @@ +#if Forms +using System; +using System.Linq; +using System.Runtime.Serialization; +using System.Text; +using System.Windows.Forms; + +namespace UELib.Core +{ + [Serializable] + [System.Runtime.InteropServices.ComVisible(false)] + public class ObjectNode : TreeNode, IDecompilableObject + { + public IUnrealDecompilable Object { get; private set; } + + public ObjectNode(IUnrealDecompilable objectRef) + { + Object = objectRef; + } + + protected ObjectNode(SerializationInfo info, StreamingContext context) : base(info, context) + { + info.AddValue(Text, Object); + } + + public virtual string Decompile() + { + try + { + UDecompilingState.ResetTabs(); + return Object.Decompile(); + } + catch (Exception e) + { + return string.Format + ( + "An exception of type \"{0}\" occurred while decompiling {1}.\r\nDetails:\r\n{2}", + e.GetType().Name, Text, e + ); + } + } + } + + [System.Runtime.InteropServices.ComVisible(false)] + public class DefaultObjectNode : ObjectNode + { + public DefaultObjectNode(IUnrealDecompilable objectRef) : base(objectRef) + { + ImageKey = nameof(UDefaultProperty); + SelectedImageKey = ImageKey; + } + } + + [System.Runtime.InteropServices.ComVisible(false)] + public sealed class ObjectListNode : TreeNode, IUnrealDecompilable + { + public ObjectListNode() + { + ImageKey = "TreeView"; + SelectedImageKey = ImageKey; + } + + public ObjectListNode(string imageName) + { + ImageKey = imageName; + SelectedImageKey = imageName; + } + + public string Decompile() + { + var output = new StringBuilder(); + foreach (var node in Nodes.OfType()) + { + output.AppendLine(node.Decompile()); + } + + return output.ToString(); + } + } +} +#endif \ No newline at end of file diff --git a/src/UnrealInterfaces.cs b/src/UnrealInterfaces.cs index 11eeb844..23029789 100644 --- a/src/UnrealInterfaces.cs +++ b/src/UnrealInterfaces.cs @@ -17,6 +17,17 @@ public interface IUnrealDecompilable string Decompile(); } + /// + /// This class has a reference to an object and are both decompilable. + /// + public interface IDecompilableObject : IUnrealDecompilable + { + /// + /// The decompileable object that will be decompiled when this object's Decompile() function is called. + /// + IUnrealDecompilable Object { get; } + } + /// /// This class has a stream reference. /// diff --git a/src/UnrealMethods.cs b/src/UnrealMethods.cs index d875e681..ecd9cddc 100644 --- a/src/UnrealMethods.cs +++ b/src/UnrealMethods.cs @@ -1,7 +1,11 @@ using System; +using System.Collections.Generic; +using System.Linq; namespace UELib { + #region Exceptions + [Serializable] public class UnrealException : Exception { @@ -21,39 +25,173 @@ public UnrealException(string message, Exception innerException) : base(message, [Serializable] public class DeserializationException : UnrealException { + [NonSerialized] private readonly string _Output; + public DeserializationException() { + _Output = "DeserializationException"; + } + + public DeserializationException(string output) : base(output) + { + _Output = output; } - public DeserializationException(string message) : base(message) + public override string ToString() { + return _Output + "\r\n" + base.ToString(); } } [Serializable] - public class DecompilationException : UnrealException + public class DecompilingCastException : DeserializationException + { + } + + [Serializable] + public class DecompilingHeaderException : UnrealException { - public DecompilationException() + [NonSerialized] private readonly string _Output; + + public DecompilingHeaderException() { + _Output = "DecompilingHeaderException"; } - public DecompilationException(string message) : base(message) + public DecompilingHeaderException(string output) + { + _Output = output; + } + + public override string ToString() + { + return _Output + "\r\n" + base.ToString(); + } + } + + [Serializable] + public class CookedPackageException : UnrealException + { + public CookedPackageException() : base("The package is cooked") + { + } + } + + [Serializable] + public class DecompressPackageException : UnrealException + { + public DecompressPackageException() : base("Failed to decompress this package") + { + } + } + + [Serializable] + public class OccurredWhileException : UnrealException + { + public OccurredWhileException(string postMessage) : base("An exception occurred while " + postMessage) + { + } + } + + [Serializable] + public class DeserializingObjectsException : OccurredWhileException + { + public DeserializingObjectsException() : base("deserializing objects") { } } - [Obsolete] - public class DeserializingObjectsException : UnrealException + [Serializable] + public class ImportingObjectsException : OccurredWhileException { + public ImportingObjectsException() : base("importing objects") + { + } } - [Obsolete] - public class ImportingObjectsException : UnrealException + [Serializable] + public class LinkingObjectsException : OccurredWhileException { + public LinkingObjectsException() : base("linking objects") + { + } } - [Obsolete] - public class LinkingObjectsException : UnrealException + #endregion + + #region Static Methods + + /// + /// Provides static methods for formating flags. + /// + public static class UnrealMethods { + public static string FlagsListToString(List flagsList) + { + var output = string.Empty; + foreach (string s in flagsList) + { + output += s + (s != flagsList.Last() ? "\n" : string.Empty); + } + + return output; + } + + public static List FlagsToList(Type flagEnum, uint flagsDWORD) + { + var flagsList = new List(); + var flagValues = Enum.GetValues(flagEnum); + foreach (uint flag in flagValues) + { + if ((flagsDWORD & flag) != flag) + continue; + + string eName = Enum.GetName(flagEnum, flag); + if (flagsList.Contains(eName)) + continue; + + flagsList.Add($"0x{flag:X8}:{eName}"); + } + + return flagsList; + } + + public static List FlagsToList(Type flagEnum, ulong flagsDWORD) + { + var flagsList = new List(); + var flagValues = Enum.GetValues(flagEnum); + foreach (ulong flag in flagValues) + { + if ((flagsDWORD & flag) != flag) + continue; + + string eName = Enum.GetName(flagEnum, flag); + if (flagsList.Contains(eName)) + continue; + + flagsList.Add($"0x{flag:X8}:{eName}"); + } + + return flagsList; + } + + public static List FlagsToList(Type flagEnum, Type flagEnum2, ulong flagsQWORD) + { + var list = FlagsToList(flagEnum, flagsQWORD); + list.AddRange(FlagsToList(flagEnum2, flagsQWORD >> 32)); + return list; + } + + public static string FlagToString(uint flags) + { + return $"0x{$"{flags:X4}".PadLeft(8, '0')}"; + } + + public static string FlagToString(ulong flags) + { + return $"{FlagToString((uint)(flags >> 32))}-{FlagToString((uint)flags)}"; + } } + + #endregion } \ No newline at end of file From 728ccdbd5ae4976598d398987441605065143eda Mon Sep 17 00:00:00 2001 From: Eliot Date: Mon, 25 Mar 2024 04:33:04 +0100 Subject: [PATCH 2/4] Revert "Auxiliary commit to revert individual files from 8c7d3993bf4079007acafbff30517c3e9eb0643f" This reverts commit 9a520fbe580d225dbb0a0c2d4d3239c4e78723bb. --- src/UnrealConfig.cs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/UnrealConfig.cs b/src/UnrealConfig.cs index 078a5a70..ef625d82 100644 --- a/src/UnrealConfig.cs +++ b/src/UnrealConfig.cs @@ -23,6 +23,15 @@ public static class UnrealConfig public static string PreEndBracket = "\r\n{0}"; public static string Indention = "\t"; + [Obsolete] + public enum CookedPlatform + { + PC, + Console + } + + [Obsolete] + public static CookedPlatform Platform; public static Dictionary> VariableTypes; #endregion @@ -37,4 +46,4 @@ public static string PrintEndBracket() return $"{string.Format(PreEndBracket, UDecompilingState.Tabs)}{ScriptConstants.EndBracket}"; } } -} +} \ No newline at end of file From a9c9a28584f1a2c4bcfe525f5c33bd38865143db Mon Sep 17 00:00:00 2001 From: Eliot Date: Mon, 25 Mar 2024 22:31:29 +0100 Subject: [PATCH 3/4] Fix accidental removal of call to ConstructObjects(); --- src/UnrealPackage.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/UnrealPackage.cs b/src/UnrealPackage.cs index 34142f28..b67dbb54 100644 --- a/src/UnrealPackage.cs +++ b/src/UnrealPackage.cs @@ -1712,6 +1712,7 @@ public void InitializePackage(InitFlags initFlags = InitFlags.All) return; } + ConstructObjects(); if ((initFlags & InitFlags.Deserialize) == 0) return; From 6968579e2a37e9374e76dbac56208faf4c307d59 Mon Sep 17 00:00:00 2001 From: Eliot Date: Mon, 25 Mar 2024 23:01:21 +0100 Subject: [PATCH 4/4] Add code fallbacks for backwards-compatibility. --- src/BinaryMetaData.cs | 27 ++++--- src/Branch/DefaultEngineBranch.cs | 22 +++--- src/Branch/EngineBranch.cs | 2 +- src/Branch/UE2/AA2/CryptoDecoder.AA2.cs | 2 +- src/Branch/UE4/EngineBranch.UE4.cs | 16 ++-- src/Core/Classes/UClassDecompiler.cs | 8 +- src/Core/Classes/UEnumDecompiler.cs | 2 +- src/Core/Classes/UFunctionDecompiler.cs | 2 +- src/Core/Classes/UObject.cs | 2 +- src/Core/Classes/UObjectDecompiler.cs | 5 ++ src/Core/Classes/UStateDecompiler.cs | 2 +- src/Core/Classes/UStructDecompiler.cs | 2 +- src/Core/Tables/UExportTableItem.cs | 20 ++++- src/Core/Tables/UGenerationTableItem.cs | 8 ++ src/Core/Tables/UImportTableItem.cs | 10 +++ src/Core/Tables/UObjectTableItem.cs | 16 +++- src/Eliot.UELib.csproj | 3 + src/Engine/Classes/UPolys.cs | 2 +- src/UnrealFlags.cs | 99 ++++++++++++++++++++++++- src/UnrealInterfaces.cs | 13 +++- src/UnrealMethods.cs | 1 + src/UnrealPackage.cs | 78 +++++++++++-------- src/UnrealStream.cs | 2 +- 23 files changed, 263 insertions(+), 81 deletions(-) diff --git a/src/BinaryMetaData.cs b/src/BinaryMetaData.cs index 4ce39a94..afec15e6 100644 --- a/src/BinaryMetaData.cs +++ b/src/BinaryMetaData.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Diagnostics; using UELib.Annotations; @@ -37,6 +38,14 @@ public struct BinaryField : IUnrealDecompilable /// public long Size { get; set; } + [Obsolete("Use Field")] + public string Name => Field; + + [Obsolete("Use Value")] + public object Tag => Value; + + [Obsolete("Use Offset")] public int Position => (int)Offset; + /// /// Decompiles and returns the output of @Tag. /// @@ -57,20 +66,20 @@ public string Decompile() /// /// Adds a new field to the @Fields stack. /// - /// Name of the field - /// Value of the field - /// Position in bytes where the field is read from + /// Name of the field + /// Value of the field + /// Position in bytes where the field is read from /// Size in bytes of the field - public void AddField(string name, object tag, long position, long size) + public void AddField(string field, object value, long offset, long size) { - Debug.Assert(size > 0, $"Size of field {name} at {position} cannot be less than 1"); + //Debug.Assert(size > 0, $"Size of field {field} at {offset} cannot be less than 1"); Fields.Push ( new BinaryField { - Field = name, - Value = tag, - Offset = position, + Field = field, + Value = value, + Offset = offset, Size = size } ); diff --git a/src/Branch/DefaultEngineBranch.cs b/src/Branch/DefaultEngineBranch.cs index 13ca5b28..3054c87b 100644 --- a/src/Branch/DefaultEngineBranch.cs +++ b/src/Branch/DefaultEngineBranch.cs @@ -128,34 +128,34 @@ public DefaultEngineBranch(BuildGeneration generation) : base(generation) public override void Setup(UnrealPackage linker) { SetupEnumPackageFlags(linker); - EnumFlagsMap.Add(typeof(PackageFlags), PackageFlags); + EnumFlagsMap.Add(typeof(PackageFlag), PackageFlags); } protected virtual void SetupEnumPackageFlags(UnrealPackage linker) { - PackageFlags[(int)Flags.PackageFlags.AllowDownload] = (uint)PackageFlagsDefault.AllowDownload; - PackageFlags[(int)Flags.PackageFlags.ClientOptional] = (uint)PackageFlagsDefault.ClientOptional; - PackageFlags[(int)Flags.PackageFlags.ServerSideOnly] = (uint)PackageFlagsDefault.ServerSideOnly; + PackageFlags[(int)Flags.PackageFlag.AllowDownload] = (uint)PackageFlagsDefault.AllowDownload; + PackageFlags[(int)Flags.PackageFlag.ClientOptional] = (uint)PackageFlagsDefault.ClientOptional; + PackageFlags[(int)Flags.PackageFlag.ServerSideOnly] = (uint)PackageFlagsDefault.ServerSideOnly; #if UE1 // FIXME: Version if (linker.Version > 61 && linker.Version <= 69) // <= UT99 - PackageFlags[(int)Flags.PackageFlags.Encrypted] = (uint)PackageFlagsUE1.Encrypted; + PackageFlags[(int)Flags.PackageFlag.Encrypted] = (uint)PackageFlagsUE1.Encrypted; #endif #if UE2 if (linker.Build == BuildGeneration.UE2_5) - PackageFlags[(int)Flags.PackageFlags.Official] = (uint)PackageFlagsUE2.Official; + PackageFlags[(int)Flags.PackageFlag.Official] = (uint)PackageFlagsUE2.Official; #endif #if UE3 // Map the new PackageFlags, but the version is nothing but a guess! if (linker.Version >= 180) { if (linker.Version >= UnrealPackage.PackageFileSummary.VCookerVersion) - PackageFlags[(int)Flags.PackageFlags.Cooked] = (uint)PackageFlagsUE3.Cooked; + PackageFlags[(int)Flags.PackageFlag.Cooked] = (uint)PackageFlagsUE3.Cooked; - PackageFlags[(int)Flags.PackageFlags.ContainsMap] = (uint)PackageFlagsUE3.ContainsMap; - PackageFlags[(int)Flags.PackageFlags.ContainsDebugData] = (uint)PackageFlagsUE3.ContainsDebugData; - PackageFlags[(int)Flags.PackageFlags.ContainsScript] = (uint)PackageFlagsUE3.ContainsScript; - PackageFlags[(int)Flags.PackageFlags.StrippedSource] = (uint)PackageFlagsUE3.StrippedSource; + PackageFlags[(int)Flags.PackageFlag.ContainsMap] = (uint)PackageFlagsUE3.ContainsMap; + PackageFlags[(int)Flags.PackageFlag.ContainsDebugData] = (uint)PackageFlagsUE3.ContainsDebugData; + PackageFlags[(int)Flags.PackageFlag.ContainsScript] = (uint)PackageFlagsUE3.ContainsScript; + PackageFlags[(int)Flags.PackageFlag.StrippedSource] = (uint)PackageFlagsUE3.StrippedSource; } #endif } diff --git a/src/Branch/EngineBranch.cs b/src/Branch/EngineBranch.cs index 141b4bbc..a4977e7c 100644 --- a/src/Branch/EngineBranch.cs +++ b/src/Branch/EngineBranch.cs @@ -32,7 +32,7 @@ public abstract class EngineBranch /// public readonly Dictionary EnumFlagsMap = new Dictionary(); - protected readonly ulong[] PackageFlags = new ulong[(int)Flags.PackageFlags.Max]; + protected readonly ulong[] PackageFlags = new ulong[(int)Flags.PackageFlag.Max]; public EngineBranch() { diff --git a/src/Branch/UE2/AA2/CryptoDecoder.AA2.cs b/src/Branch/UE2/AA2/CryptoDecoder.AA2.cs index b46f63ad..58df0ed3 100644 --- a/src/Branch/UE2/AA2/CryptoDecoder.AA2.cs +++ b/src/Branch/UE2/AA2/CryptoDecoder.AA2.cs @@ -3,7 +3,7 @@ namespace UELib.Branch.UE2.AA2 { - // TODO: Re-implement as a BaseStream wrapper (in UELib 2.0) + // TODO: Re-implement as a BaseStream wrapper public class CryptoDecoderAA2 : IBufferDecoder { public void PreDecode(IUnrealStream stream) diff --git a/src/Branch/UE4/EngineBranch.UE4.cs b/src/Branch/UE4/EngineBranch.UE4.cs index 81d0bb41..7d549af5 100644 --- a/src/Branch/UE4/EngineBranch.UE4.cs +++ b/src/Branch/UE4/EngineBranch.UE4.cs @@ -41,20 +41,20 @@ public EngineBranchUE4() : base(BuildGeneration.UE4) public override void Setup(UnrealPackage linker) { SetupEnumPackageFlags(linker); - EnumFlagsMap.Add(typeof(PackageFlags), PackageFlags); + EnumFlagsMap.Add(typeof(PackageFlag), PackageFlags); } protected virtual void SetupEnumPackageFlags(UnrealPackage linker) { - PackageFlags[(int)Flags.PackageFlags.ClientOptional] = + PackageFlags[(int)Flags.PackageFlag.ClientOptional] = (uint)DefaultEngineBranch.PackageFlagsDefault.ClientOptional; - PackageFlags[(int)Flags.PackageFlags.ServerSideOnly] = + PackageFlags[(int)Flags.PackageFlag.ServerSideOnly] = (uint)DefaultEngineBranch.PackageFlagsDefault.ServerSideOnly; - PackageFlags[(int)Flags.PackageFlags.EditorOnly] = (uint)PackageFlagsUE4.EditorOnly; - PackageFlags[(int)Flags.PackageFlags.Cooked] = (uint)PackageFlagsUE4.Cooked; - PackageFlags[(int)Flags.PackageFlags.UnversionedProperties] = (uint)PackageFlagsUE4.UnversionedProperties; - PackageFlags[(int)Flags.PackageFlags.ReloadingForCooker] = (uint)PackageFlagsUE4.ReloadingForCooker; - PackageFlags[(int)Flags.PackageFlags.FilterEditorOnly] = (uint)PackageFlagsUE4.FilterEditorOnly; + PackageFlags[(int)Flags.PackageFlag.EditorOnly] = (uint)PackageFlagsUE4.EditorOnly; + PackageFlags[(int)Flags.PackageFlag.Cooked] = (uint)PackageFlagsUE4.Cooked; + PackageFlags[(int)Flags.PackageFlag.UnversionedProperties] = (uint)PackageFlagsUE4.UnversionedProperties; + PackageFlags[(int)Flags.PackageFlag.ReloadingForCooker] = (uint)PackageFlagsUE4.ReloadingForCooker; + PackageFlags[(int)Flags.PackageFlag.FilterEditorOnly] = (uint)PackageFlagsUE4.FilterEditorOnly; } protected override void SetupSerializer(UnrealPackage linker) diff --git a/src/Core/Classes/UClassDecompiler.cs b/src/Core/Classes/UClassDecompiler.cs index 0bbfd90e..4530b7e5 100644 --- a/src/Core/Classes/UClassDecompiler.cs +++ b/src/Core/Classes/UClassDecompiler.cs @@ -78,25 +78,25 @@ public override string Decompile() return content; } - [Obsolete] + [Obsolete("Deprecated", true)] public string GetDependencies() { throw new NotImplementedException(); } - [Obsolete] + [Obsolete("Deprecated", true)] private string GetImports() { throw new NotImplementedException(); } - [Obsolete] + [Obsolete("Deprecated", true)] public string GetStats() { throw new NotImplementedException(); } - protected override string FormatHeader() + public override string FormatHeader() { string output = (IsClassInterface() ? "interface " : "class ") + Name; string metaData = DecompileMeta(); diff --git a/src/Core/Classes/UEnumDecompiler.cs b/src/Core/Classes/UEnumDecompiler.cs index 66645134..d9ed305f 100644 --- a/src/Core/Classes/UEnumDecompiler.cs +++ b/src/Core/Classes/UEnumDecompiler.cs @@ -20,7 +20,7 @@ public override string Decompile() UnrealConfig.PrintEndBracket() + ";"; } - protected virtual string FormatHeader() + public override string FormatHeader() { return $"enum {Name}{DecompileMeta()}"; } diff --git a/src/Core/Classes/UFunctionDecompiler.cs b/src/Core/Classes/UFunctionDecompiler.cs index 9588f33f..d4ff6bdd 100644 --- a/src/Core/Classes/UFunctionDecompiler.cs +++ b/src/Core/Classes/UFunctionDecompiler.cs @@ -215,7 +215,7 @@ private string FormatFlags() return output; } - protected override string FormatHeader() + public override string FormatHeader() { var output = string.Empty; // static function (string?:) Name(Parms)... diff --git a/src/Core/Classes/UObject.cs b/src/Core/Classes/UObject.cs index 57a0f013..cbf2ac11 100644 --- a/src/Core/Classes/UObject.cs +++ b/src/Core/Classes/UObject.cs @@ -670,7 +670,7 @@ public virtual void PostInitialize() { } - [Obsolete] + [Obsolete("Deprecated", true)] public virtual void InitializeImports() { throw new NotImplementedException(); diff --git a/src/Core/Classes/UObjectDecompiler.cs b/src/Core/Classes/UObjectDecompiler.cs index 8ce188e2..31f505fd 100644 --- a/src/Core/Classes/UObjectDecompiler.cs +++ b/src/Core/Classes/UObjectDecompiler.cs @@ -37,6 +37,11 @@ public virtual string Decompile() $"// Reference: {Class.Name}'{GetOuterGroup()}'"; } + public virtual string FormatHeader() + { + return GetReferencePath(); + } + protected string DecompileProperties() { if (Properties == null || Properties.Count == 0) diff --git a/src/Core/Classes/UStateDecompiler.cs b/src/Core/Classes/UStateDecompiler.cs index df7172c5..3128e066 100644 --- a/src/Core/Classes/UStateDecompiler.cs +++ b/src/Core/Classes/UStateDecompiler.cs @@ -55,7 +55,7 @@ private string GetEdit() return HasStateFlag(Flags.StateFlags.Editable) ? "()" : string.Empty; } - protected override string FormatHeader() + public override string FormatHeader() { var output = $"{GetAuto()}{GetSimulated()}state{GetEdit()} {Name}"; if (Super != null && Super.Name != Name diff --git a/src/Core/Classes/UStructDecompiler.cs b/src/Core/Classes/UStructDecompiler.cs index 76dfbd75..82fbb1ba 100644 --- a/src/Core/Classes/UStructDecompiler.cs +++ b/src/Core/Classes/UStructDecompiler.cs @@ -49,7 +49,7 @@ public override string Decompile() return content + UnrealConfig.PrintEndBracket() + ";"; } - protected virtual string FormatHeader() + public override string FormatHeader() { var output = $"struct {FormatFlags()}{Name}{(Super != null ? $" {FormatExtends()} {Super.Name}" : string.Empty)}"; string metaData = DecompileMeta(); diff --git a/src/Core/Tables/UExportTableItem.cs b/src/Core/Tables/UExportTableItem.cs index cda305d0..7bc7a608 100644 --- a/src/Core/Tables/UExportTableItem.cs +++ b/src/Core/Tables/UExportTableItem.cs @@ -25,6 +25,7 @@ public int ClassIndex get => _ClassIndex; set => _ClassIndex = value; } + [CanBeNull] public UObjectTableItem Class => Owner.GetIndexTable(ClassIndex); @@ -54,9 +55,14 @@ public int ArchetypeIndex } [CanBeNull] public UObjectTableItem Archetype => Owner.GetIndexTable(_ArchetypeIndex); + + [Obsolete("Use Class"), Browsable(false)] public UObjectTableItem ClassTable => Owner.GetIndexTable(_ClassIndex); + + [Obsolete] + protected override int __ClassIndex => _ClassIndex; - [Obsolete, Browsable(false)] public UObjectTableItem SuperTable => Owner.GetIndexTable(_SuperIndex); - [Obsolete, Browsable(false)] + [Obsolete("Use Super"), Browsable(false)] public UObjectTableItem SuperTable => Owner.GetIndexTable(_SuperIndex); + [Obsolete("Use Super?.ObjectName"), Browsable(false)] public string SuperName { get @@ -66,8 +72,8 @@ public string SuperName } } - [Obsolete, Browsable(false)] public UObjectTableItem ArchetypeTable => Owner.GetIndexTable(_ArchetypeIndex); - [Obsolete, Browsable(false)] + [Obsolete("Use Archetype"), Browsable(false)] public UObjectTableItem ArchetypeTable => Owner.GetIndexTable(_ArchetypeIndex); + [Obsolete("Use Archetype?.ObjectName"), Browsable(false)] public string ArchetypeName { get @@ -296,6 +302,12 @@ public override string ToString() return $"{ObjectName}({Index}{1})"; } + [Obsolete("Use ToString()")] + public string ToString(bool v) + { + return ToString(); + } + public static explicit operator int(UExportTableItem item) { return item.Index; diff --git a/src/Core/Tables/UGenerationTableItem.cs b/src/Core/Tables/UGenerationTableItem.cs index 8e74cfe9..8389467c 100644 --- a/src/Core/Tables/UGenerationTableItem.cs +++ b/src/Core/Tables/UGenerationTableItem.cs @@ -1,3 +1,4 @@ +using System; using UELib.Annotations; namespace UELib @@ -27,6 +28,13 @@ public int NetObjectCount set => _NetObjectCount = value; } + [Obsolete] + public object ExportsCount => ExportCount; + [Obsolete] + public object NamesCount => NameCount; + [Obsolete] + public object NetObjectsCount => NetObjectCount; + public const int VNetObjectsCount = 322; public void Serialize(IUnrealStream stream) diff --git a/src/Core/Tables/UImportTableItem.cs b/src/Core/Tables/UImportTableItem.cs index 0d531c6a..5d09a02a 100644 --- a/src/Core/Tables/UImportTableItem.cs +++ b/src/Core/Tables/UImportTableItem.cs @@ -1,3 +1,4 @@ +using System; using UELib.Core; namespace UELib @@ -25,6 +26,9 @@ public UName ClassName set => _ClassName = value; } + [Obsolete] protected override string __ClassName => _ClassName; + [Obsolete] protected override int __ClassIndex => (int)_ClassName; + #endregion public void Serialize(IUnrealStream stream) @@ -53,6 +57,12 @@ public override string ToString() return $"{ObjectName}({-(Index + 1)})"; } + [Obsolete("Use ToString()")] + public string ToString(bool v) + { + return ToString(); + } + public static explicit operator int(UImportTableItem item) { return -item.Index; diff --git a/src/Core/Tables/UObjectTableItem.cs b/src/Core/Tables/UObjectTableItem.cs index 6c8e028b..c863d024 100644 --- a/src/Core/Tables/UObjectTableItem.cs +++ b/src/Core/Tables/UObjectTableItem.cs @@ -42,11 +42,11 @@ public int OuterIndex } [Obsolete, Browsable(false)] public UNameTableItem ObjectTable => Owner.Names[(int)_ObjectName]; - [Obsolete, Browsable(false)] public UObjectTableItem ClassTable => null; + [Obsolete("Use UExportTableItem.Class"), Browsable(false)] public UObjectTableItem ClassTable => Owner.GetIndexTable(ClassIndex); [Obsolete, Browsable(false)] public UObjectTableItem OuterTable => Owner.GetIndexTable(OuterIndex); public UObjectTableItem Outer => Owner.GetIndexTable(_OuterIndex); - [Obsolete, Browsable(false)] + [Obsolete("Use Outer?.ObjectName"), Browsable(false)] public string OuterName { get @@ -56,6 +56,18 @@ public string OuterName } } + [Obsolete("Use UExportTableItem.ClassIndex"), Browsable(false)] + public int ClassIndex => __ClassIndex; + + [Obsolete] + protected virtual int __ClassIndex => 0; + + [Obsolete("Use Class?.ObjectName or UImportTableItem.ClassName"), Browsable(false)] + public string ClassName => __ClassName; + + [Obsolete] + protected virtual string __ClassName => ""; + #endregion public IEnumerable EnumerateOuter() diff --git a/src/Eliot.UELib.csproj b/src/Eliot.UELib.csproj index 2cb974ec..4b414b9a 100644 --- a/src/Eliot.UELib.csproj +++ b/src/Eliot.UELib.csproj @@ -64,6 +64,9 @@ 6.0.0 + + + Eliot.UELib.nuspec diff --git a/src/Engine/Classes/UPolys.cs b/src/Engine/Classes/UPolys.cs index 804a8828..8f7c9df7 100644 --- a/src/Engine/Classes/UPolys.cs +++ b/src/Engine/Classes/UPolys.cs @@ -28,7 +28,7 @@ protected override void Deserialize() base.Deserialize(); // Faster serialization for cooked packages, no don't have to check for the package's version here. - if (Package.Summary.PackageFlags.HasFlag(PackageFlags.Cooked)) + if (Package.Summary.PackageFlags.HasFlag(PackageFlag.Cooked)) { ElementOwner = _Buffer.ReadObject(); Record(nameof(ElementOwner), ElementOwner); diff --git a/src/UnrealFlags.cs b/src/UnrealFlags.cs index 2dac174b..7300a041 100644 --- a/src/UnrealFlags.cs +++ b/src/UnrealFlags.cs @@ -75,7 +75,7 @@ public override string ToString() /// /// /// - public enum PackageFlags + public enum PackageFlag { AllowDownload, ClientOptional, @@ -104,6 +104,103 @@ public enum PackageFlags Max, } + [Obsolete("Use the normalized PackageFlag instead")] + [Flags] + public enum PackageFlags : uint + { + // 028A0009 : A cooked and compressed package + // 00280009 : A cooked package + // 00020001 : A ordinary package + + /// + /// UEX: Whether clients are allowed to download the package from the server. + /// UE4: Displaced by "NewlyCreated" + /// + AllowDownload = 0x00000001U, + + /// + /// Whether clients can skip downloading the package but still able to join the server. + /// + ClientOptional = 0x00000002U, + + /// + /// Only necessary to load on the server. + /// + ServerSideOnly = 0x00000004U, + + BrokenLinks = 0x00000008U, // @Redefined(UE3, Cooked) + + /// + /// The package is cooked. + /// + Cooked = 0x00000008U, // @Redefined + + /// + /// ??? + /// <= UT + /// + Unsecure = 0x00000010U, + + /// + /// The package is encrypted. + /// <= UT + /// Also attested in file UT2004/Packages.MD5 but it is not encrypted. + /// + Encrypted = 0x00000020U, + +#if UE4 + EditorOnly = 0x00000040U, + UnversionedProperties = 0x00002000U, +#endif + + /// + /// Clients must download the package. + /// + Need = 0x00008000U, + + /// + /// Unknown flags + /// - 0x20000000 -- Probably means the package contains Content(Meshes, Textures) + /// + /// + + /// Package holds map data. + ContainsMap = 0x00020000U, + + /// + /// Package contains classes. + /// + ContainsScript = 0x00200000U, + + /// + /// The package was build with -Debug + /// + ContainsDebugData = 0x00400000U, + + Imports = 0x00800000U, + + Compressed = 0x02000000U, + FullyCompressed = 0x04000000U, + + /// + /// Whether package has metadata exported(anything related to the editor). + /// + NoExportsData = 0x20000000U, + + /// + /// Package's source is stripped. + /// UE4: Same as ReloadingForCooker? + /// + Stripped = 0x40000000U, +#if UE4 + FilterEditorOnly = 0x80000000U, +#endif + Protected = 0x80000000U, +#if TRANSFORMERS + HMS_XmlFormat = 0x80000000U, +#endif + } + [Flags] public enum CompressionFlags : uint { diff --git a/src/UnrealInterfaces.cs b/src/UnrealInterfaces.cs index 23029789..a3d34af0 100644 --- a/src/UnrealInterfaces.cs +++ b/src/UnrealInterfaces.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.IO; using UELib.Annotations; using UELib.Core; @@ -20,6 +21,7 @@ public interface IUnrealDecompilable /// /// This class has a reference to an object and are both decompilable. /// + [Obsolete] public interface IDecompilableObject : IUnrealDecompilable { /// @@ -123,6 +125,15 @@ public interface IUnrealExportable void SerializeExport(string desiredExportExtension, Stream exportStream); } + public static class IUnrealExportableImplementation + { + [Obsolete("Use CanExport()")] + public static bool CompatableExport(this IUnrealExportable exportable) + { + return exportable.CanExport(); + } + } + /// /// This class is replicable. /// diff --git a/src/UnrealMethods.cs b/src/UnrealMethods.cs index ecd9cddc..97ad0e61 100644 --- a/src/UnrealMethods.cs +++ b/src/UnrealMethods.cs @@ -124,6 +124,7 @@ public LinkingObjectsException() : base("linking objects") /// /// Provides static methods for formating flags. /// + [Obsolete("Use .ToString() on the target enum instead.")] public static class UnrealMethods { public static string FlagsListToString(List flagsList) diff --git a/src/UnrealPackage.cs b/src/UnrealPackage.cs index b67dbb54..5a1f9f23 100644 --- a/src/UnrealPackage.cs +++ b/src/UnrealPackage.cs @@ -775,11 +775,13 @@ public struct PackageFileSummary : IUnrealSerializableClass public uint UE4Version; public uint UE4LicenseeVersion; - public UnrealFlags PackageFlags; + public UnrealFlags PackageFlags; + [Obsolete] private const int VHeaderSize = 249; public int HeaderSize; + [Obsolete] private const int VFolderName = 269; /// @@ -799,6 +801,7 @@ public struct PackageFileSummary : IUnrealSerializableClass /// public UArray Heritages; + [Obsolete] private const int VDependsOffset = 415; public int DependsOffset; @@ -808,29 +811,39 @@ public struct PackageFileSummary : IUnrealSerializableClass private PackageFileEngineVersion PackageEngineVersion; private PackageFileEngineVersion PackageCompatibleEngineVersion; + [Obsolete] private const int VEngineVersion = 245; - public int EngineVersion; + + [Obsolete] public const int VCookerVersion = 277; + + public int EngineVersion; public int CookerVersion; + [Obsolete] private const int VCompression = 334; public uint CompressionFlags; public UArray CompressedChunks; + [Obsolete] private const int VPackageSource = 482; public uint PackageSource; + [Obsolete] private const int VAdditionalPackagesToCook = 516; public UArray AdditionalPackagesToCook; + [Obsolete] private const int VImportExportGuidsOffset = 623; public int ImportExportGuidsOffset; public int ImportGuidsCount; public int ExportGuidsCount; + [Obsolete] private const int VThumbnailTableOffset = 584; public int ThumbnailTableOffset; + [Obsolete] private const int VTextureAllocations = 767; public int GatherableTextDataCount; @@ -844,7 +857,6 @@ public struct PackageFileSummary : IUnrealSerializableClass public UGuid PersistentGuid; public UGuid OwnerPersistentGuid; - // In UELib 2.0 we pass the version to the Archives instead. private void SetupBuild(UnrealPackage package) { // Auto-detect @@ -995,7 +1007,7 @@ public void Deserialize(IUnrealStream stream) FolderName = stream.ReadText(); } - PackageFlags = stream.ReadFlags32(); + PackageFlags = stream.ReadFlags32(); Console.WriteLine("Package Flags:" + PackageFlags); #if HAWKEN if (stream.Package.Build == GameBuild.BuildName.Hawken && @@ -1107,7 +1119,7 @@ public void Deserialize(IUnrealStream stream) #endif #if DD2 // No version check found in the .exe - if (stream.Package.Build == GameBuild.BuildName.DD2 && PackageFlags.HasFlag(Flags.PackageFlags.Cooked)) + if (stream.Package.Build == GameBuild.BuildName.DD2 && PackageFlags.HasFlag(PackageFlag.Cooked)) stream.Skip(4); #endif if (stream.Version >= VThumbnailTableOffset) @@ -1280,7 +1292,7 @@ public void Deserialize(IUnrealStream stream) } #if ROCKETLEAGUE if (stream.Package.Build == GameBuild.BuildName.RocketLeague - && PackageFlags.HasFlag(Flags.PackageFlags.Cooked)) + && PackageFlags.HasFlag(PackageFlag.Cooked)) { int garbageSize = stream.ReadInt32(); Debug.WriteLine(garbageSize, "GarbageSize"); @@ -1302,19 +1314,21 @@ public void Deserialize(IUnrealStream stream) /// public bool IsBigEndianEncoded { get; } + [Obsolete] public const int VSIZEPREFIXDEPRECATED = 64; + + [Obsolete] public const int VINDEXDEPRECATED = 178; - /// - /// DLLBind(Name) - /// + [Obsolete] public const int VDLLBIND = 655; - /// - /// New class modifier "ClassGroup(Name[,Name])" - /// + [Obsolete] public const int VCLASSGROUP = 789; + [Obsolete] + public const int VCOOKEDPACKAGES = 277; + public uint Version => Summary.Version; /// @@ -1422,7 +1436,7 @@ public void Deserialize(IUnrealStream stream) [PublicAPI] public NativesTablePackage NTLPackage; - [Obsolete("See UPackageStream.Decoder")] + [Obsolete("See UPackageStream.Decoder", true)] public IBufferDecoder Decoder; #endregion @@ -1686,7 +1700,7 @@ public void InitializeExportObjects(InitFlags initFlags = InitFlags.All) /// Constructs all import objects. /// /// If TRUE initialize all constructed objects. - [PublicAPI] + [Obsolete("Pending deprecation")] public void InitializeImportObjects(bool initialize = true) { Objects = new List(Imports.Count); @@ -2092,30 +2106,30 @@ public UObject FindObjectByGroup(string objectGroup) [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool IsConsoleCooked() { - return Summary.PackageFlags.HasFlag(Flags.PackageFlags.Cooked) + return Summary.PackageFlags.HasFlag(PackageFlag.Cooked) && CookerPlatform == BuildPlatform.Console; } /// - /// Checks whether this package is marked with @flag. + /// Checks whether this package is marked with @flags. /// - /// The enum @flag to test. + /// The enum @flag to test. /// Whether this package is marked with @flag. - [Obsolete] - public bool HasPackageFlag(PackageFlags flag) + [Obsolete("See Summary.PackageFlags.HasFlag")] + public bool HasPackageFlag(PackageFlags flags) { - return (PackageFlags & (uint)flag) != 0; + return Summary.PackageFlags.HasFlags((uint)flags); } /// - /// Checks whether this package is marked with @flag. + /// Checks whether this package is marked with @flags. /// - /// The uint @flag to test + /// The uint @flag to test /// Whether this package is marked with @flag. - [Obsolete] - public bool HasPackageFlag(uint flag) + [Obsolete("See Summary.PackageFlags.HasFlag")] + public bool HasPackageFlag(uint flags) { - return (PackageFlags & flag) != 0; + return (PackageFlags & flags) != 0; } /// @@ -2125,7 +2139,7 @@ public bool HasPackageFlag(uint flag) [Obsolete] public bool IsCooked() { - return Summary.PackageFlags.HasFlag(Flags.PackageFlags.Cooked); + return Summary.PackageFlags.HasFlag(PackageFlag.Cooked); } /// @@ -2135,7 +2149,7 @@ public bool IsCooked() [Obsolete] public bool IsMap() { - return Summary.PackageFlags.HasFlag(Flags.PackageFlags.ContainsMap); + return Summary.PackageFlags.HasFlag(PackageFlag.ContainsMap); } /// @@ -2145,7 +2159,7 @@ public bool IsMap() [Obsolete] public bool IsScript() { - return Summary.PackageFlags.HasFlag(Flags.PackageFlags.ContainsScript); + return Summary.PackageFlags.HasFlag(PackageFlag.ContainsScript); } /// @@ -2155,7 +2169,7 @@ public bool IsScript() [Obsolete] public bool IsDebug() { - return Summary.PackageFlags.HasFlag(Flags.PackageFlags.ContainsDebugData); + return Summary.PackageFlags.HasFlag(PackageFlag.ContainsDebugData); } /// @@ -2165,7 +2179,7 @@ public bool IsDebug() [Obsolete] public bool IsStripped() { - return Summary.PackageFlags.HasFlag(Flags.PackageFlags.StrippedSource); + return Summary.PackageFlags.HasFlag(PackageFlag.StrippedSource); } /// @@ -2175,13 +2189,13 @@ public bool IsStripped() [Obsolete] public bool IsEncrypted() { - return Summary.PackageFlags.HasFlag(Flags.PackageFlags.Encrypted); + return Summary.PackageFlags.HasFlag(PackageFlag.Encrypted); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool ContainsEditorData() { - return Summary.UE4Version > 0 && !Summary.PackageFlags.HasFlag(Flags.PackageFlags.FilterEditorOnly); + return Summary.UE4Version > 0 && !Summary.PackageFlags.HasFlag(PackageFlag.FilterEditorOnly); } #region IBuffered diff --git a/src/UnrealStream.cs b/src/UnrealStream.cs index 7cf8006a..e0657f2e 100644 --- a/src/UnrealStream.cs +++ b/src/UnrealStream.cs @@ -685,7 +685,7 @@ public void Record(string varName, object varObject = null) /// /// Methods that shouldn't be duplicated between UObjectStream and UPackageStream. /// - [Obsolete("Don't use directly, in 2.0 these are implemented once in a single shared IUnrealStream")] + [Obsolete("Pending deprecation")] public static class UnrealStreamImplementations { [MethodImpl(MethodImplOptions.AggressiveInlining)]