From 6454e59415b3873daa971210711effcb55c7742f Mon Sep 17 00:00:00 2001 From: Eliot Date: Wed, 4 Sep 2024 15:31:40 +0200 Subject: [PATCH] Fix https://github.com/UE-Explorer/UE-Explorer/issues/61 --- src/Core/Classes/UDefaultProperty.cs | 953 +++++++++++++------------- src/Core/Classes/UObjectDecompiler.cs | 3 +- src/UnrealScript/PropertyDisplay.cs | 20 +- 3 files changed, 499 insertions(+), 477 deletions(-) diff --git a/src/Core/Classes/UDefaultProperty.cs b/src/Core/Classes/UDefaultProperty.cs index a649c07..f35a5d0 100644 --- a/src/Core/Classes/UDefaultProperty.cs +++ b/src/Core/Classes/UDefaultProperty.cs @@ -90,7 +90,7 @@ public string Decompile() string expr = name; return ArrayIndex > 0 - ? $"{expr}[{ArrayIndex}]={value}" + ? $"{expr}{PropertyDisplay.FormatT3DElementAccess(ArrayIndex.ToString(), _Buffer.Version)}={value}" : $"{expr}={value}"; } @@ -142,6 +142,7 @@ private T FindProperty(out UStruct outer) break; } + break; } @@ -274,6 +275,7 @@ private int DeserializeTagArrayIndexUE1() byte e = _Buffer.ReadByte(); arrayIndex = ((b & 0x3F) << 24) + (c << 16) + (d << 8) + e; } + return arrayIndex; } @@ -341,17 +343,17 @@ private bool DeserializeTagUE1() break; case PropertyType.ArrayProperty: - { -#if DNF - if (_Buffer.Package.Build == UnrealPackage.GameBuild.BuildName.DNF && - _Buffer.Version >= 124) { - _Buffer.Read(out _TypeData.InnerTypeName); - Record(nameof(_TypeData.InnerTypeName), _TypeData.InnerTypeName); - } +#if DNF + if (_Buffer.Package.Build == UnrealPackage.GameBuild.BuildName.DNF && + _Buffer.Version >= 124) + { + _Buffer.Read(out _TypeData.InnerTypeName); + Record(nameof(_TypeData.InnerTypeName), _TypeData.InnerTypeName); + } #endif - break; - } + break; + } } Size = DeserializePackedSize((byte)(info & InfoSizeMask)); @@ -510,7 +512,7 @@ private void DeserializeTypeDataUE3() // GOTYE didn't apply this upgrade, but did the EnumName update? ... && _Buffer.Package.Build != UnrealPackage.GameBuild.BuildName.Borderlands_GOTYE #endif - ) + ) { BoolValue = _Buffer.ReadByte() > 0; } @@ -570,8 +572,9 @@ private string TryDeserializeDefaultPropertyValue(PropertyType type, ref Deseria } catch (Exception ex) { - Console.Error.WriteLine($"\r\n> PropertyTag value deserialization error for {_Container.GetPath()}.{Name}" + - $"\r\n Exception: {ex}"); + Console.Error.WriteLine( + $"\r\n> PropertyTag value deserialization error for {_Container.GetPath()}.{Name}" + + $"\r\n Exception: {ex}"); return $"/* ERROR: {ex.GetType()} */"; } @@ -596,71 +599,71 @@ private string DeserializeDefaultPropertyValue(PropertyType type, ref Deserializ switch (type) { case PropertyType.BoolProperty: - { - bool value; - if (Size == 0) - { - Debug.Assert(BoolValue != null, nameof(BoolValue) + " != null"); - value = BoolValue.Value; - } - else { - value = _Buffer.ReadByte() > 0; - } + bool value; + if (Size == 0) + { + Debug.Assert(BoolValue != null, nameof(BoolValue) + " != null"); + value = BoolValue.Value; + } + else + { + value = _Buffer.ReadByte() > 0; + } - Record(nameof(value), value); - propertyValue = value ? "true" : "false"; - break; - } + Record(nameof(value), value); + propertyValue = value ? "true" : "false"; + break; + } case PropertyType.StrProperty: - { - string value = _Buffer.ReadString(); - Record(nameof(value), value); - propertyValue = PropertyDisplay.FormatLiteral(value); - break; - } + { + string value = _Buffer.ReadString(); + Record(nameof(value), value); + propertyValue = PropertyDisplay.FormatLiteral(value); + break; + } case PropertyType.NameProperty: - { - var value = _Buffer.ReadNameReference(); - Record(nameof(value), value); - propertyValue = $"\"{value}\""; - break; - } + { + var value = _Buffer.ReadNameReference(); + Record(nameof(value), value); + propertyValue = $"\"{value}\""; + break; + } #if GIGANTIC case PropertyType.JsonRefProperty: - { - var jsonObjectName = _Buffer.ReadNameReference(); - var jsonObject = _Buffer.ReadObject(); - - if (jsonObject == null) { - propertyValue = "none"; + var jsonObjectName = _Buffer.ReadNameReference(); + var jsonObject = _Buffer.ReadObject(); + + if (jsonObject == null) + { + propertyValue = "none"; + break; + } + + // !!! Could be null for imports + //Contract.Assert(jsonObject.Class != null); + propertyValue = $"JsonRef<{jsonObject.GetClassName()}>'{jsonObjectName}'"; break; } - - // !!! Could be null for imports - //Contract.Assert(jsonObject.Class != null); - propertyValue = $"JsonRef<{jsonObject.GetClassName()}>'{jsonObjectName}'"; - break; - } #endif case PropertyType.IntProperty: - { - int value = _Buffer.ReadInt32(); - Record(nameof(value), value); - propertyValue = PropertyDisplay.FormatLiteral(value); - break; - } + { + int value = _Buffer.ReadInt32(); + Record(nameof(value), value); + propertyValue = PropertyDisplay.FormatLiteral(value); + break; + } #if BIOSHOCK case PropertyType.QwordProperty: - { - long value = _Buffer.ReadInt64(); - Record(nameof(value), value); - propertyValue = PropertyDisplay.FormatLiteral(value); - break; - } + { + long value = _Buffer.ReadInt64(); + Record(nameof(value), value); + propertyValue = PropertyDisplay.FormatLiteral(value); + break; + } case PropertyType.XWeakReferenceProperty: propertyValue = "/* XWeakReference: (?=" + _Buffer.ReadName() + ",?=" + _Buffer.ReadName() + @@ -668,545 +671,553 @@ private string DeserializeDefaultPropertyValue(PropertyType type, ref Deserializ break; #endif case PropertyType.FloatProperty: - { - float value = _Buffer.ReadFloat(); - Record(nameof(value), value); - propertyValue = PropertyDisplay.FormatLiteral(value); - break; - } - - case PropertyType.ByteProperty: - { - if (_Buffer.Version >= (uint)PackageObjectLegacyVersion.EnumTagNameAddedToBytePropertyTag && - Size == 8) - { - string enumTagName = _Buffer.ReadName(); - Record(nameof(enumTagName), enumTagName); - propertyValue = _Buffer.Version >= - (uint)PackageObjectLegacyVersion.EnumNameAddedToBytePropertyTag - ? $"{_TypeData.EnumName}.{enumTagName}" - : enumTagName; - } - else { - byte value = _Buffer.ReadByte(); + float value = _Buffer.ReadFloat(); Record(nameof(value), value); propertyValue = PropertyDisplay.FormatLiteral(value); + break; } - break; - } + case PropertyType.ByteProperty: + { + if (_Buffer.Version >= (uint)PackageObjectLegacyVersion.EnumTagNameAddedToBytePropertyTag && + Size == 8) + { + string enumTagName = _Buffer.ReadName(); + Record(nameof(enumTagName), enumTagName); + propertyValue = _Buffer.Version >= + (uint)PackageObjectLegacyVersion.EnumNameAddedToBytePropertyTag + ? $"{_TypeData.EnumName}.{enumTagName}" + : enumTagName; + } + else + { + byte value = _Buffer.ReadByte(); + Record(nameof(value), value); + propertyValue = PropertyDisplay.FormatLiteral(value); + } + + break; + } case PropertyType.InterfaceProperty: - { - var interfaceClass = _Buffer.ReadObject(); - Record(nameof(interfaceClass), interfaceClass); - propertyValue = PropertyDisplay.FormatLiteral(interfaceClass); - break; - } - - case PropertyType.ComponentProperty: - case PropertyType.ObjectProperty: - { - var constantObject = _Buffer.ReadObject(); - Record(nameof(constantObject), constantObject); - if (constantObject == null) { - // =none - propertyValue = "none"; + var interfaceClass = _Buffer.ReadObject(); + Record(nameof(interfaceClass), interfaceClass); + propertyValue = PropertyDisplay.FormatLiteral(interfaceClass); break; } - Debug.Assert(UDecompilingState.s_inlinedSubObjects != null, "UDecompilingState.s_inlinedSubObjects != null"); - - bool isPendingInline = - UDecompilingState.s_inlinedSubObjects.TryGetValue(constantObject, out bool isInlined); - // If the object is part of the current container, then it probably was an inlined declaration. - bool shouldInline = constantObject.Outer == _Container - && !isPendingInline - && !isInlined; - if (shouldInline) + case PropertyType.ComponentProperty: + case PropertyType.ObjectProperty: { - if ((deserializeFlags & DeserializeFlags.WithinStruct) == 0) + var constantObject = _Buffer.ReadObject(); + Record(nameof(constantObject), constantObject); + if (constantObject == null) + { + // =none + propertyValue = "none"; + break; + } + + Debug.Assert(UDecompilingState.s_inlinedSubObjects != null, + "UDecompilingState.s_inlinedSubObjects != null"); + + bool isPendingInline = + UDecompilingState.s_inlinedSubObjects.TryGetValue(constantObject, out bool isInlined); + // If the object is part of the current container, then it probably was an inlined declaration. + bool shouldInline = constantObject.Outer == _Container + && !isPendingInline + && !isInlined; + if (shouldInline) { - UDecompilingState.s_inlinedSubObjects.Add(constantObject, true); - - // Unknown objects are only deserialized on demand. - constantObject.BeginDeserializing(); - - propertyValue = constantObject.Decompile() + "\r\n"; - - _TempFlags |= DoNotAppendName; - if ((deserializeFlags & DeserializeFlags.WithinArray) != 0) + if ((deserializeFlags & DeserializeFlags.WithinStruct) == 0) { - _TempFlags |= ReplaceNameMarker; - propertyValue += $"{UDecompilingState.Tabs}%ARRAYNAME%={constantObject.Name}"; + UDecompilingState.s_inlinedSubObjects.Add(constantObject, true); + + // Unknown objects are only deserialized on demand. + constantObject.BeginDeserializing(); + + propertyValue = constantObject.Decompile() + "\r\n"; + + _TempFlags |= DoNotAppendName; + if ((deserializeFlags & DeserializeFlags.WithinArray) != 0) + { + _TempFlags |= ReplaceNameMarker; + propertyValue += $"{UDecompilingState.Tabs}%ARRAYNAME%={constantObject.Name}"; + + break; + } + + propertyValue += $"{UDecompilingState.Tabs}{Name}={constantObject.Name}"; break; } - propertyValue += $"{UDecompilingState.Tabs}{Name}={constantObject.Name}"; + // Within a struct, to be inlined later on! + UDecompilingState.s_inlinedSubObjects.Add(constantObject, false); + propertyValue = $"{Name}={constantObject.Name}"; break; } - // Within a struct, to be inlined later on! - UDecompilingState.s_inlinedSubObjects.Add(constantObject, false); - propertyValue = $"{Name}={constantObject.Name}"; - + // Use shorthand for inlined objects. + propertyValue = isInlined + ? constantObject.Name + : PropertyDisplay.FormatLiteral(constantObject); + break; } - // Use shorthand for inlined objects. - propertyValue = isInlined - ? constantObject.Name - : PropertyDisplay.FormatLiteral(constantObject); - - break; - } - case PropertyType.ClassProperty: - { - var classObject = _Buffer.ReadObject(); - Record(nameof(classObject), classObject); - propertyValue = PropertyDisplay.FormatLiteral(classObject); - break; - } + { + var classObject = _Buffer.ReadObject(); + Record(nameof(classObject), classObject); + propertyValue = PropertyDisplay.FormatLiteral(classObject); + break; + } - // Old StringProperty with a fixed size and null termination. + // Old StringProperty with a fixed size and null termination. case PropertyType.StringProperty when _Buffer.Version < 100: - { - string str = _Buffer.ReadAnsiNullString(); - propertyValue = str; - break; - } - + { + string str = _Buffer.ReadAnsiNullString(); + propertyValue = str; + break; + } + case PropertyType.DelegateProperty when _Buffer.Version >= 100: - { - // Can by any object, usually a class. - var functionOwner = _Buffer.ReadObject(); - Record(nameof(functionOwner), functionOwner); + { + // Can by any object, usually a class. + var functionOwner = _Buffer.ReadObject(); + Record(nameof(functionOwner), functionOwner); - string functionName = _Buffer.ReadName(); - Record(nameof(functionName), functionName); + string functionName = _Buffer.ReadName(); + Record(nameof(functionName), functionName); - // Can be null in UE3 packages - propertyValue = functionOwner != null - ? $"{functionOwner.Name}.{functionName}" - : $"{functionName}"; - break; - } + // Can be null in UE3 packages + propertyValue = functionOwner != null + ? $"{functionOwner.Name}.{functionName}" + : $"{functionName}"; + break; + } #region HardCoded Struct Types case PropertyType.Color: - { - _Buffer.ReadStructMarshal(out UColor color); - propertyValue += $"R={PropertyDisplay.FormatLiteral(color.R)}," + - $"G={PropertyDisplay.FormatLiteral(color.G)}," + - $"B={PropertyDisplay.FormatLiteral(color.B)}," + - $"A={PropertyDisplay.FormatLiteral(color.A)}"; - break; - } + { + _Buffer.ReadStructMarshal(out UColor color); + propertyValue += $"R={PropertyDisplay.FormatLiteral(color.R)}," + + $"G={PropertyDisplay.FormatLiteral(color.G)}," + + $"B={PropertyDisplay.FormatLiteral(color.B)}," + + $"A={PropertyDisplay.FormatLiteral(color.A)}"; + break; + } case PropertyType.LinearColor: - { - _Buffer.ReadStructMarshal(out ULinearColor color); - propertyValue += $"R={PropertyDisplay.FormatLiteral(color.R)}," + - $"G={PropertyDisplay.FormatLiteral(color.G)}," + - $"B={PropertyDisplay.FormatLiteral(color.B)}," + - $"A={PropertyDisplay.FormatLiteral(color.A)}"; - break; - } + { + _Buffer.ReadStructMarshal(out ULinearColor color); + propertyValue += $"R={PropertyDisplay.FormatLiteral(color.R)}," + + $"G={PropertyDisplay.FormatLiteral(color.G)}," + + $"B={PropertyDisplay.FormatLiteral(color.B)}," + + $"A={PropertyDisplay.FormatLiteral(color.A)}"; + break; + } case PropertyType.Vector2D: - { - _Buffer.ReadStructMarshal(out UVector2D vector); - propertyValue += $"X={PropertyDisplay.FormatLiteral(vector.X)}," + - $"Y={PropertyDisplay.FormatLiteral(vector.Y)}"; - break; - } + { + _Buffer.ReadStructMarshal(out UVector2D vector); + propertyValue += $"X={PropertyDisplay.FormatLiteral(vector.X)}," + + $"Y={PropertyDisplay.FormatLiteral(vector.Y)}"; + break; + } case PropertyType.Vector: - { - _Buffer.ReadStructMarshal(out UVector vector); - propertyValue += $"X={PropertyDisplay.FormatLiteral(vector.X)}," + - $"Y={PropertyDisplay.FormatLiteral(vector.Y)}," + - $"Z={PropertyDisplay.FormatLiteral(vector.Z)}"; - break; - } + { + _Buffer.ReadStructMarshal(out UVector vector); + propertyValue += $"X={PropertyDisplay.FormatLiteral(vector.X)}," + + $"Y={PropertyDisplay.FormatLiteral(vector.Y)}," + + $"Z={PropertyDisplay.FormatLiteral(vector.Z)}"; + break; + } case PropertyType.Vector4: - { - _Buffer.ReadStructMarshal(out UVector4 vector); - propertyValue += $"X={PropertyDisplay.FormatLiteral(vector.X)}," + - $"Y={PropertyDisplay.FormatLiteral(vector.Y)}," + - $"Z={PropertyDisplay.FormatLiteral(vector.Z)}," + - $"W={PropertyDisplay.FormatLiteral(vector.W)}"; - break; - } + { + _Buffer.ReadStructMarshal(out UVector4 vector); + propertyValue += $"X={PropertyDisplay.FormatLiteral(vector.X)}," + + $"Y={PropertyDisplay.FormatLiteral(vector.Y)}," + + $"Z={PropertyDisplay.FormatLiteral(vector.Z)}," + + $"W={PropertyDisplay.FormatLiteral(vector.W)}"; + break; + } case PropertyType.TwoVectors: - { - string v1 = DeserializeDefaultPropertyValue(PropertyType.Vector, ref deserializeFlags); - string v2 = DeserializeDefaultPropertyValue(PropertyType.Vector, ref deserializeFlags); - propertyValue += $"v1=({v1})," + - $"v2=({v2})"; - break; - } + { + string v1 = DeserializeDefaultPropertyValue(PropertyType.Vector, ref deserializeFlags); + string v2 = DeserializeDefaultPropertyValue(PropertyType.Vector, ref deserializeFlags); + propertyValue += $"v1=({v1})," + + $"v2=({v2})"; + break; + } case PropertyType.Rotator: - { - _Buffer.ReadStructMarshal(out URotator rotator); - propertyValue += $"Pitch={rotator.Pitch}," + - $"Yaw={rotator.Yaw}," + - $"Roll={rotator.Roll}"; - break; - } + { + _Buffer.ReadStructMarshal(out URotator rotator); + propertyValue += $"Pitch={rotator.Pitch}," + + $"Yaw={rotator.Yaw}," + + $"Roll={rotator.Roll}"; + break; + } case PropertyType.Guid: - { - _Buffer.ReadStructMarshal(out UGuid guid); - propertyValue += $"A={guid.A}," + - $"B={guid.B}," + - $"C={guid.C}," + - $"D={guid.D}"; - break; - } + { + _Buffer.ReadStructMarshal(out UGuid guid); + propertyValue += $"A={guid.A}," + + $"B={guid.B}," + + $"C={guid.C}," + + $"D={guid.D}"; + break; + } case PropertyType.Sphere: - { - AssertFastSerialize(_Buffer); - _Buffer.ReadStructMarshal(out USphere sphere); - propertyValue += $"W={PropertyDisplay.FormatLiteral(sphere.W)}," + - $"X={PropertyDisplay.FormatLiteral(sphere.X)}," + - $"Y={PropertyDisplay.FormatLiteral(sphere.Y)}," + - $"Z={PropertyDisplay.FormatLiteral(sphere.Z)}"; + { + AssertFastSerialize(_Buffer); + _Buffer.ReadStructMarshal(out USphere sphere); + propertyValue += $"W={PropertyDisplay.FormatLiteral(sphere.W)}," + + $"X={PropertyDisplay.FormatLiteral(sphere.X)}," + + $"Y={PropertyDisplay.FormatLiteral(sphere.Y)}," + + $"Z={PropertyDisplay.FormatLiteral(sphere.Z)}"; - break; - } + break; + } case PropertyType.Plane: - { - AssertFastSerialize(_Buffer); - _Buffer.ReadStructMarshal(out UPlane plane); - propertyValue += $"W={PropertyDisplay.FormatLiteral(plane.W)}," + - $"X={PropertyDisplay.FormatLiteral(plane.X)}," + - $"Y={PropertyDisplay.FormatLiteral(plane.Y)}," + - $"Z={PropertyDisplay.FormatLiteral(plane.Z)}"; - break; - } + { + AssertFastSerialize(_Buffer); + _Buffer.ReadStructMarshal(out UPlane plane); + propertyValue += $"W={PropertyDisplay.FormatLiteral(plane.W)}," + + $"X={PropertyDisplay.FormatLiteral(plane.X)}," + + $"Y={PropertyDisplay.FormatLiteral(plane.Y)}," + + $"Z={PropertyDisplay.FormatLiteral(plane.Z)}"; + break; + } case PropertyType.Scale: - { - _Buffer.ReadStructMarshal(out UScale scale); - propertyValue += "Scale=(" + - $"X={PropertyDisplay.FormatLiteral(scale.Scale.X)}," + - $"Y={PropertyDisplay.FormatLiteral(scale.Scale.Y)}," + - $"Z={PropertyDisplay.FormatLiteral(scale.Scale.Z)})," + - $"SheerRate={PropertyDisplay.FormatLiteral(scale.SheerRate)}," + - $"SheerAxis={scale.SheerAxis}"; - break; - } + { + _Buffer.ReadStructMarshal(out UScale scale); + propertyValue += "Scale=(" + + $"X={PropertyDisplay.FormatLiteral(scale.Scale.X)}," + + $"Y={PropertyDisplay.FormatLiteral(scale.Scale.Y)}," + + $"Z={PropertyDisplay.FormatLiteral(scale.Scale.Z)})," + + $"SheerRate={PropertyDisplay.FormatLiteral(scale.SheerRate)}," + + $"SheerAxis={scale.SheerAxis}"; + break; + } case PropertyType.Box: - { - AssertFastSerialize(_Buffer); - string min = DeserializeDefaultPropertyValue(PropertyType.Vector, ref deserializeFlags); - string max = DeserializeDefaultPropertyValue(PropertyType.Vector, ref deserializeFlags); - string isValid = - DeserializeDefaultPropertyValue(PropertyType.ByteProperty, ref deserializeFlags); - propertyValue += $"Min=({min})," + - $"Max=({max})," + - $"IsValid={isValid}"; - break; - } + { + AssertFastSerialize(_Buffer); + string min = DeserializeDefaultPropertyValue(PropertyType.Vector, ref deserializeFlags); + string max = DeserializeDefaultPropertyValue(PropertyType.Vector, ref deserializeFlags); + string isValid = + DeserializeDefaultPropertyValue(PropertyType.ByteProperty, ref deserializeFlags); + propertyValue += $"Min=({min})," + + $"Max=({max})," + + $"IsValid={isValid}"; + break; + } case PropertyType.Quat: - { - AssertFastSerialize(_Buffer); - _Buffer.ReadStructMarshal(out UQuat quat); - propertyValue += $"X={PropertyDisplay.FormatLiteral(quat.X)}," + - $"Y={PropertyDisplay.FormatLiteral(quat.Y)}," + - $"Z={PropertyDisplay.FormatLiteral(quat.Z)}," + - $"W={PropertyDisplay.FormatLiteral(quat.W)}"; - break; - } + { + AssertFastSerialize(_Buffer); + _Buffer.ReadStructMarshal(out UQuat quat); + propertyValue += $"X={PropertyDisplay.FormatLiteral(quat.X)}," + + $"Y={PropertyDisplay.FormatLiteral(quat.Y)}," + + $"Z={PropertyDisplay.FormatLiteral(quat.Z)}," + + $"W={PropertyDisplay.FormatLiteral(quat.W)}"; + break; + } case PropertyType.Matrix: - { - AssertFastSerialize(_Buffer); - //_Buffer.ReadAtomicStruct(out UMatrix matrix); - string xPlane = DeserializeDefaultPropertyValue(PropertyType.Plane, ref deserializeFlags); - string yPlane = DeserializeDefaultPropertyValue(PropertyType.Plane, ref deserializeFlags); - string zPlane = DeserializeDefaultPropertyValue(PropertyType.Plane, ref deserializeFlags); - string wPlane = DeserializeDefaultPropertyValue(PropertyType.Plane, ref deserializeFlags); - propertyValue += $"XPlane=({xPlane}),YPlane=({yPlane}),ZPlane=({zPlane}),WPlane=({wPlane})"; - break; - } + { + AssertFastSerialize(_Buffer); + //_Buffer.ReadAtomicStruct(out UMatrix matrix); + string xPlane = DeserializeDefaultPropertyValue(PropertyType.Plane, ref deserializeFlags); + string yPlane = DeserializeDefaultPropertyValue(PropertyType.Plane, ref deserializeFlags); + string zPlane = DeserializeDefaultPropertyValue(PropertyType.Plane, ref deserializeFlags); + string wPlane = DeserializeDefaultPropertyValue(PropertyType.Plane, ref deserializeFlags); + propertyValue += $"XPlane=({xPlane}),YPlane=({yPlane}),ZPlane=({zPlane}),WPlane=({wPlane})"; + break; + } case PropertyType.IntPoint: - { - string x = DeserializeDefaultPropertyValue(PropertyType.IntProperty, ref deserializeFlags); - string y = DeserializeDefaultPropertyValue(PropertyType.IntProperty, ref deserializeFlags); - propertyValue += $"X={x},Y={y}"; - break; - } + { + string x = DeserializeDefaultPropertyValue(PropertyType.IntProperty, ref deserializeFlags); + string y = DeserializeDefaultPropertyValue(PropertyType.IntProperty, ref deserializeFlags); + propertyValue += $"X={x},Y={y}"; + break; + } case PropertyType.PointRegion: - { - string zone = DeserializeDefaultPropertyValue(PropertyType.ObjectProperty, ref deserializeFlags); - string iLeaf = DeserializeDefaultPropertyValue(PropertyType.IntProperty, ref deserializeFlags); - string zoneNumber = - DeserializeDefaultPropertyValue(PropertyType.ByteProperty, ref deserializeFlags); - propertyValue += $"Zone={zone},iLeaf={iLeaf},ZoneNumber={zoneNumber}"; - break; - } + { + string zone = + DeserializeDefaultPropertyValue(PropertyType.ObjectProperty, ref deserializeFlags); + string iLeaf = DeserializeDefaultPropertyValue(PropertyType.IntProperty, ref deserializeFlags); + string zoneNumber = + DeserializeDefaultPropertyValue(PropertyType.ByteProperty, ref deserializeFlags); + propertyValue += $"Zone={zone},iLeaf={iLeaf},ZoneNumber={zoneNumber}"; + break; + } #endregion case PropertyType.StructProperty: - { - deserializeFlags |= DeserializeFlags.WithinStruct; -#if DNF - if (_Buffer.Package.Build == UnrealPackage.GameBuild.BuildName.DNF) { - goto nonAtomic; - } + deserializeFlags |= DeserializeFlags.WithinStruct; +#if DNF + if (_Buffer.Package.Build == UnrealPackage.GameBuild.BuildName.DNF) + { + goto nonAtomic; + } #endif - // Ugly hack, but this will do for now until this entire function gets "rewritten" :D - if (Enum.TryParse(_TypeData.StructName, out PropertyType structPropertyType)) - { - // Not atomic if <=UE2, - // TODO: Figure out all non-atomic structs - if (_Buffer.Version < (uint)PackageObjectLegacyVersion.FastSerializeStructs) + // Ugly hack, but this will do for now until this entire function gets "rewritten" :D + if (Enum.TryParse(_TypeData.StructName, out PropertyType structPropertyType)) { - switch (structPropertyType) + // Not atomic if <=UE2, + // TODO: Figure out all non-atomic structs + if (_Buffer.Version < (uint)PackageObjectLegacyVersion.FastSerializeStructs) { - case PropertyType.Quat: - case PropertyType.Scale: // not available in UE3 - case PropertyType.Matrix: - case PropertyType.Box: - case PropertyType.Plane: - goto nonAtomic; - - // None of these exist in older packages (UE2 or older). - case PropertyType.LinearColor: - case PropertyType.Vector2D: - case PropertyType.Vector4: - goto nonAtomic; + switch (structPropertyType) + { + case PropertyType.Quat: + case PropertyType.Scale: // not available in UE3 + case PropertyType.Matrix: + case PropertyType.Box: + case PropertyType.Plane: + goto nonAtomic; + + // None of these exist in older packages (UE2 or older). + case PropertyType.LinearColor: + case PropertyType.Vector2D: + case PropertyType.Vector4: + goto nonAtomic; + } } - } - else - { - switch (structPropertyType) + else { - //case PropertyType.Coords: - //case PropertyType.Range: - // Deprecated in UDK - case PropertyType.PointRegion: - goto nonAtomic; + switch (structPropertyType) + { + //case PropertyType.Coords: + //case PropertyType.Range: + // Deprecated in UDK + case PropertyType.PointRegion: + goto nonAtomic; + } } - } - propertyValue += DeserializeDefaultPropertyValue(structPropertyType, ref deserializeFlags); - goto output; - } + propertyValue += DeserializeDefaultPropertyValue(structPropertyType, ref deserializeFlags); + goto output; + } - nonAtomic: - // We have to modify the outer so that dynamic arrays within this struct - // will be able to find its variables to determine the array type. - FindProperty(out _Outer); - var structTags = new LinkedList(); - bool hasMore = true; - while (true) - { - var tag = new UDefaultProperty(_Container, _Outer); - try + nonAtomic: + // We have to modify the outer so that dynamic arrays within this struct + // will be able to find its variables to determine the array type. + FindProperty(out _Outer); + var structTags = new LinkedList(); + bool hasMore = true; + while (true) { - // Might throw an exception if the struct is atomic - if (tag.Deserialize()) + var tag = new UDefaultProperty(_Container, _Outer); + try + { + // Might throw an exception if the struct is atomic + if (tag.Deserialize()) + { + structTags.AddLast(tag); + continue; + } + } + catch (Exception ex) { - structTags.AddLast(tag); - continue; + // ignored } + + break; } - catch (Exception ex) + + foreach (var tag in structTags) { - // ignored + string tagExpr = tag.Name; + if (tag.ArrayIndex > 0) + { + tagExpr += PropertyDisplay.FormatT3DElementAccess(tag.ArrayIndex.ToString(), _Buffer.Version); + } + + propertyValue += $"{tagExpr}={tag.Value}"; + + if (tag != structTags.Last.Value) + { + propertyValue += ","; + } } + output: + propertyValue = propertyValue.Length != 0 + ? $"({propertyValue})" + : "none"; break; } - foreach (var tag in structTags) + case PropertyType.ArrayProperty: { - string tagExpr = tag.Name; - if (tag.ArrayIndex > 0) + int arraySize = _Buffer.ReadIndex(); + Record(nameof(arraySize), arraySize); + if (arraySize == 0) { - tagExpr += $"[{tag.ArrayIndex}]"; + propertyValue = "none"; + break; } - propertyValue += $"{tagExpr}={tag.Value}"; - if (tag != structTags.Last.Value) + var arrayType = PropertyType.None; + if (_TypeData.InnerTypeName != null && !Enum.TryParse(_TypeData.InnerTypeName, out arrayType)) { - propertyValue += ","; + throw new Exception( + $"Couldn't convert InnerTypeName \"{_TypeData.InnerTypeName}\" to PropertyType"); } - } - - output: - propertyValue = propertyValue.Length != 0 - ? $"({propertyValue})" - : "none"; - break; - } - case PropertyType.ArrayProperty: - { - int arraySize = _Buffer.ReadIndex(); - Record(nameof(arraySize), arraySize); - if (arraySize == 0) - { - propertyValue = "none"; - break; - } - - var arrayType = PropertyType.None; - if (_TypeData.InnerTypeName != null && !Enum.TryParse(_TypeData.InnerTypeName, out arrayType)) - { - throw new Exception( - $"Couldn't convert InnerTypeName \"{_TypeData.InnerTypeName}\" to PropertyType"); - } - - // Find the property within the outer/owner or its inheritances. - // If found it has to modify the outer so structs within this array can find their array variables. - // Additionally we need to know the property to determine the array's type. - if (arrayType == PropertyType.None) - { - var property = FindProperty(out _Outer); - if (property?.InnerProperty != null) + // Find the property within the outer/owner or its inheritances. + // If found it has to modify the outer so structs within this array can find their array variables. + // Additionally we need to know the property to determine the array's type. + if (arrayType == PropertyType.None) { - arrayType = property.InnerProperty.Type; - } - // If we did not find a reference to the associated property(because of imports) - // then try to determine the array's type by scanning the defined array types. - else if (UnrealConfig.VariableTypes != null && UnrealConfig.VariableTypes.ContainsKey(Name)) - { - var varTuple = UnrealConfig.VariableTypes[Name]; - if (varTuple != null) + var property = FindProperty(out _Outer); + if (property?.InnerProperty != null) { - arrayType = varTuple.Item2; + arrayType = property.InnerProperty.Type; + } + // If we did not find a reference to the associated property(because of imports) + // then try to determine the array's type by scanning the defined array types. + else if (UnrealConfig.VariableTypes != null && UnrealConfig.VariableTypes.ContainsKey(Name)) + { + var varTuple = UnrealConfig.VariableTypes[Name]; + if (varTuple != null) + { + arrayType = varTuple.Item2; + } } - } - } - - if (arrayType == PropertyType.None) - { - propertyValue = "/* Array type was not detected. */"; - break; - } - - deserializeFlags |= DeserializeFlags.WithinArray; - if ((deserializeFlags & DeserializeFlags.WithinStruct) != 0) - { - // Hardcoded fix for InterpCurve and InterpCurvePoint. - if (string.Compare(Name, "Points", StringComparison.OrdinalIgnoreCase) == 0) - { - arrayType = PropertyType.StructProperty; } - for (var i = 0; i < arraySize; ++i) + if (arrayType == PropertyType.None) { - propertyValue += DeserializeDefaultPropertyValue(arrayType, ref deserializeFlags) - + (i != arraySize - 1 ? "," : string.Empty); + propertyValue = "/* Array type was not detected. */"; + break; } - propertyValue = $"({propertyValue})"; - } - else - { - for (var i = 0; i < arraySize; ++i) + deserializeFlags |= DeserializeFlags.WithinArray; + if ((deserializeFlags & DeserializeFlags.WithinStruct) != 0) { - string elementValue = DeserializeDefaultPropertyValue(arrayType, ref deserializeFlags); - if ((_TempFlags & ReplaceNameMarker) != 0) + // Hardcoded fix for InterpCurve and InterpCurvePoint. + if (string.Compare(Name, "Points", StringComparison.OrdinalIgnoreCase) == 0) { - propertyValue += elementValue.Replace("%ARRAYNAME%", $"{Name}({i})"); - _TempFlags = 0x00; + arrayType = PropertyType.StructProperty; } - else + + for (var i = 0; i < arraySize; ++i) { - propertyValue += $"{Name}({i})={elementValue}"; + propertyValue += DeserializeDefaultPropertyValue(arrayType, ref deserializeFlags) + + (i != arraySize - 1 ? "," : string.Empty); } - if (i != arraySize - 1) + propertyValue = $"({propertyValue})"; + } + else + { + for (var i = 0; i < arraySize; ++i) { - propertyValue += "\r\n" + UDecompilingState.Tabs; + string elementAccessText = + PropertyDisplay.FormatT3DElementAccess(i.ToString(), _Buffer.Version); + string elementValue = DeserializeDefaultPropertyValue(arrayType, ref deserializeFlags); + if ((_TempFlags & ReplaceNameMarker) != 0) + { + propertyValue += elementValue.Replace("%ARRAYNAME%", $"{Name}{elementAccessText}"); + _TempFlags = 0x00; + } + else + { + propertyValue += $"{Name}{elementAccessText}={elementValue}"; + } + + if (i != arraySize - 1) + { + propertyValue += "\r\n" + UDecompilingState.Tabs; + } } } - } - - _TempFlags |= DoNotAppendName; - break; - } - case PropertyType.MapProperty: - { - if (Size == 0) break; - - int count = _Buffer.ReadIndex(); - Record(nameof(count), count); - - var property = FindProperty(out _Outer); - if (property == null) - { - propertyValue = "// Unable to decompile Map data."; + _TempFlags |= DoNotAppendName; break; } - propertyValue = "("; - for (int i = 0; i < count; ++i) + case PropertyType.MapProperty: { - propertyValue += DeserializeDefaultPropertyValue(property.ValueProperty.Type, ref deserializeFlags); - if (i + 1 != count) + if (Size == 0) break; + + int count = _Buffer.ReadIndex(); + Record(nameof(count), count); + + var property = FindProperty(out _Outer); + if (property == null) { - propertyValue += ","; + propertyValue = "// Unable to decompile Map data."; + break; } - } - propertyValue += ")"; - break; - } - case PropertyType.FixedArrayProperty: - { - // We require the InnerProperty to properly deserialize this data type. - var property = FindProperty(out _Outer); - if (property == null) - { - propertyValue = "// Unable to decompile FixedArray data."; + propertyValue = "("; + for (int i = 0; i < count; ++i) + { + propertyValue += + DeserializeDefaultPropertyValue(property.ValueProperty.Type, ref deserializeFlags); + if (i + 1 != count) + { + propertyValue += ","; + } + } + + propertyValue += ")"; break; } - var innerType = property.InnerProperty.Type; - propertyValue = "("; - for (int i = 0; i < property.Count; ++i) + case PropertyType.FixedArrayProperty: { - propertyValue += DeserializeDefaultPropertyValue(innerType, ref deserializeFlags); - if (i + 1 != property.Count) + // We require the InnerProperty to properly deserialize this data type. + var property = FindProperty(out _Outer); + if (property == null) + { + propertyValue = "// Unable to decompile FixedArray data."; + break; + } + + var innerType = property.InnerProperty.Type; + propertyValue = "("; + for (int i = 0; i < property.Count; ++i) { - propertyValue += ","; + propertyValue += DeserializeDefaultPropertyValue(innerType, ref deserializeFlags); + if (i + 1 != property.Count) + { + propertyValue += ","; + } } + + propertyValue += ")"; + break; } - propertyValue += ")"; - break; - } // Note: We don't have to verify the package's version here. case PropertyType.PointerProperty: - { - int offset = _Buffer.ReadInt32(); - propertyValue = PropertyDisplay.FormatLiteral(offset); - break; - } + { + int offset = _Buffer.ReadInt32(); + propertyValue = PropertyDisplay.FormatLiteral(offset); + break; + } default: throw new Exception($"Unsupported property tag type {Type}"); diff --git a/src/Core/Classes/UObjectDecompiler.cs b/src/Core/Classes/UObjectDecompiler.cs index a7fc924..838bd13 100644 --- a/src/Core/Classes/UObjectDecompiler.cs +++ b/src/Core/Classes/UObjectDecompiler.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.Linq; +using UELib.UnrealScript; namespace UELib.Core { @@ -82,7 +83,7 @@ protected string DecompileProperties() && Properties[i].ArrayIndex <= 0 && Properties[i + 1].ArrayIndex > 0) { - propertyText = propertyText.Insert(Properties[i].Name.Length, "[0]"); + propertyText = propertyText.Insert(Properties[i].Name.Length, PropertyDisplay.FormatT3DElementAccess("0", _Buffer.Version)); } propertiesText += $"{UDecompilingState.Tabs}{propertyText}\r\n"; diff --git a/src/UnrealScript/PropertyDisplay.cs b/src/UnrealScript/PropertyDisplay.cs index f41816d..e42a38f 100644 --- a/src/UnrealScript/PropertyDisplay.cs +++ b/src/UnrealScript/PropertyDisplay.cs @@ -1,4 +1,5 @@ -using System.Globalization; +using System; +using System.Globalization; using System.Runtime.CompilerServices; using System.Text; using UELib.Core; @@ -98,8 +99,8 @@ public static string FormatLiteral(ulong input) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string FormatLiteral(UObject input) { - return input != null - ? input.GetReferencePath() + return input != null + ? input.GetReferencePath() : "none"; } @@ -116,17 +117,26 @@ public static string FormatExport(ref UVector input) $"{FormatExport(input.Y)}," + $"{FormatExport(input.Z)}"; } - + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string FormatOffset(short input) { return $"{input:X3}h"; } - + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string FormatOffset(int input) { return $"{input:X4}h"; } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static string FormatT3DElementAccess(string index, uint version) + { + // FIXME: version + return version >= 100 + ? $"[{index}]" + : $"({index})"; + } } }