/// <summary> /// Tries to read all properties that resides in this object instance. /// </summary> protected void DeserializeProperties() { Default = this; _Properties = new DefaultPropertiesCollection(); while (true) { var tag = new UDefaultProperty(Default); if (!tag.Deserialize()) { break; } _Properties.Add(tag); } // We need to keep the MemoryStream alive, // because we first deserialize the defaultproperties but we skip the values, which we'll deserialize later on by demand. if (Properties.Count == 0) { _Properties = null; } }
/// <summary> /// Deserialize a default property value of a specified type. /// </summary> /// <param name="type">Kind of type to try deserialize.</param> /// <returns>The deserialized value if any.</returns> private string DeserializeDefaultPropertyValue(PropertyType type, ref DeserializeFlags deserializeFlags) { if (_Buffer.Position - _ValueOffset > Size) { throw new DeserializationException("End of defaultproperties stream reached..."); } var orgOuter = _Outer; string propertyValue = String.Empty; try { // Deserialize Value switch (type) { case PropertyType.BoolProperty: { var value = _BoolValue; if (Size == 1 && _Buffer.Version < V3) { value = _Buffer.ReadByte() > 0; } propertyValue = value ? "true" : "false"; break; } case PropertyType.StrProperty: propertyValue = "\"" + _Buffer.ReadText().Escape() + "\""; break; case PropertyType.NameProperty: propertyValue = _Buffer.ReadName(); break; case PropertyType.IntProperty: propertyValue = _Buffer.ReadInt32().ToString(CultureInfo.InvariantCulture); break; case PropertyType.QWordProperty: propertyValue = _Buffer.ReadInt64().ToString(CultureInfo.InvariantCulture); break; case PropertyType.FloatProperty: propertyValue = _Buffer.ReadFloat().ToUFloat(); break; case PropertyType.ByteProperty: if (_Buffer.Version >= V3 && Size == 8) { var enumValue = _Buffer.ReadName(); propertyValue = enumValue; if (_Buffer.Version >= VEnumName) { propertyValue = EnumName + "." + propertyValue; } } else { propertyValue = _Buffer.ReadByte().ToString(CultureInfo.InvariantCulture); } break; case PropertyType.InterfaceProperty: case PropertyType.ComponentProperty: case PropertyType.ObjectProperty: { var uObject = _Buffer.ReadObject(); uObjects.Add(uObject); _Container.Record("object", uObject); if (uObject != null) { bool inline = false; // If true, object is an archetype or subobject. if (uObject.Outer == _Container && (deserializeFlags & DeserializeFlags.WithinStruct) == 0) { // Unknown objects are only deserialized on demand. uObject.BeginDeserializing(); if (uObject.Properties != null && uObject.Properties.Count > 0) { inline = true; propertyValue = uObject.Decompile() + "\r\n" + UDecompilingState.Tabs; _TempFlags |= DoNotAppendName; if ((deserializeFlags & DeserializeFlags.WithinArray) != 0) { _TempFlags |= ReplaceNameMarker; propertyValue += "%ARRAYNAME%=" + uObject.Name; } else { propertyValue += Name + "=" + uObject.Name; } } } if (!inline) { // =CLASS'Package.Group(s)+.Name' propertyValue = String.Format("{0}\'{1}\'", uObject.GetClassName(), uObject.GetOuterGroup()); } } else { // =none propertyValue = "none"; } break; } case PropertyType.ClassProperty: { var uObject = _Buffer.ReadObject(); uObjects.Add(uObject); _Container.Record("object", uObject); propertyValue = (uObject != null ? "class\'" + uObject.Name + "\'" : "none"); break; } case PropertyType.DelegateProperty: { _TempFlags |= DoNotAppendName; int outerIndex = _Buffer.ReadObjectIndex(); // Where the assigned delegate property exists. var delegateValue = _Buffer.ReadName(); string delegateName = ((string)(Name)).Substring(2, Name.Length - 12); propertyValue = delegateName + "=" + delegateValue; break; } #region HardCoded Struct Types case PropertyType.Color: { string b = DeserializeDefaultPropertyValue(PropertyType.ByteProperty, ref deserializeFlags); string g = DeserializeDefaultPropertyValue(PropertyType.ByteProperty, ref deserializeFlags); string r = DeserializeDefaultPropertyValue(PropertyType.ByteProperty, ref deserializeFlags); string a = DeserializeDefaultPropertyValue(PropertyType.ByteProperty, ref deserializeFlags); propertyValue += "R=" + r + ",G=" + g + ",B=" + b + ",A=" + a; break; } case PropertyType.LinearColor: { string b = DeserializeDefaultPropertyValue(PropertyType.FloatProperty, ref deserializeFlags); string g = DeserializeDefaultPropertyValue(PropertyType.FloatProperty, ref deserializeFlags); string r = DeserializeDefaultPropertyValue(PropertyType.FloatProperty, ref deserializeFlags); string a = DeserializeDefaultPropertyValue(PropertyType.FloatProperty, ref deserializeFlags); propertyValue += "R=" + r + ",G=" + g + ",B=" + b + ",A=" + a; break; } case PropertyType.Vector: { string x = DeserializeDefaultPropertyValue(PropertyType.FloatProperty, ref deserializeFlags); string y = DeserializeDefaultPropertyValue(PropertyType.FloatProperty, ref deserializeFlags); string z = DeserializeDefaultPropertyValue(PropertyType.FloatProperty, ref deserializeFlags); propertyValue += "X=" + x + ",Y=" + y + ",Z=" + z; break; } case PropertyType.TwoVectors: { string v1 = DeserializeDefaultPropertyValue(PropertyType.Vector, ref deserializeFlags); string v2 = DeserializeDefaultPropertyValue(PropertyType.Vector, ref deserializeFlags); propertyValue += "v1=(" + v1 + "),v2=(" + v2 + ")"; break; } case PropertyType.Vector4: { string plane = DeserializeDefaultPropertyValue(PropertyType.Plane, ref deserializeFlags); propertyValue += plane; break; } case PropertyType.Vector2D: { string x = DeserializeDefaultPropertyValue(PropertyType.FloatProperty, ref deserializeFlags); string y = DeserializeDefaultPropertyValue(PropertyType.FloatProperty, ref deserializeFlags); propertyValue += "X=" + x + ",Y=" + y; break; } case PropertyType.Rotator: { string pitch = DeserializeDefaultPropertyValue(PropertyType.IntProperty, ref deserializeFlags); string yaw = DeserializeDefaultPropertyValue(PropertyType.IntProperty, ref deserializeFlags); string roll = DeserializeDefaultPropertyValue(PropertyType.IntProperty, ref deserializeFlags); propertyValue += "Pitch=" + pitch + ",Yaw=" + yaw + ",Roll=" + roll; break; } case PropertyType.Guid: { string a = DeserializeDefaultPropertyValue(PropertyType.IntProperty, ref deserializeFlags); string b = DeserializeDefaultPropertyValue(PropertyType.IntProperty, ref deserializeFlags); string c = DeserializeDefaultPropertyValue(PropertyType.IntProperty, ref deserializeFlags); string d = DeserializeDefaultPropertyValue(PropertyType.IntProperty, ref deserializeFlags); propertyValue += "A=" + a + ",B=" + b + ",C=" + c + ",D=" + d; break; } case PropertyType.Sphere: case PropertyType.Plane: { string v = DeserializeDefaultPropertyValue(PropertyType.Vector, ref deserializeFlags); string w = DeserializeDefaultPropertyValue(PropertyType.FloatProperty, ref deserializeFlags); propertyValue += v + ",W=" + w; break; } case PropertyType.Scale: { string scale = DeserializeDefaultPropertyValue(PropertyType.Vector, ref deserializeFlags); string sheerRate = DeserializeDefaultPropertyValue(PropertyType.FloatProperty, ref deserializeFlags); string sheerAxis = DeserializeDefaultPropertyValue(PropertyType.ByteProperty, ref deserializeFlags); propertyValue += "Scale=(" + scale + ")" + ",SheerRate=" + sheerRate + ",SheerAxis=" + sheerAxis; break; } case PropertyType.Box: { 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.InterpCurve: * { * // HACK: * UPropertyTag tag = new UPropertyTag( _Owner ); * tag.Serialize(); * buffer.Seek( tag.ValueOffset, System.IO.SeekOrigin.Begin ); * * int curvescount = buffer.ReadIndex(); * if( curvescount <= 0 ) * { * break; * } * propertyvalue += tag.Name + "=("; * for( int i = 0; i < curvescount; ++ i ) * { * propertyvalue += "(" + SerializeDefaultPropertyValue( PropertyType.InterpCurvePoint, buffer, ref serializeFlags ) + ")"; * if( i != curvescount - 1 ) * { * propertyvalue += ","; * } * } * propertyvalue += ")"; * break; * }*/ /*case PropertyType.InterpCurvePoint: * { * string InVal = SerializeDefaultPropertyValue( PropertyType.Float, buffer, ref serializeFlags ); * string OutVal = SerializeDefaultPropertyValue( PropertyType.Float, buffer, ref serializeFlags ); * * propertyvalue += "InVal=" + InVal + * ",OutVal=" + OutVal; * break; * }*/ case PropertyType.Quat: { propertyValue += DeserializeDefaultPropertyValue(PropertyType.Plane, ref deserializeFlags); break; } case PropertyType.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; } #endregion case PropertyType.PointerProperty: case PropertyType.StructProperty: { deserializeFlags |= DeserializeFlags.WithinStruct; bool isHardCoded = false; var hardcodedStructs = (PropertyType[])Enum.GetValues(typeof(PropertyType)); for (var i = (byte)PropertyType.StructOffset; i < hardcodedStructs.Length; ++i) { var structType = Enum.GetName(typeof(PropertyType), (byte)hardcodedStructs[i]); if (String.Compare(ItemName, structType, StringComparison.OrdinalIgnoreCase) != 0) { continue; } isHardCoded = true; propertyValue += DeserializeDefaultPropertyValue(hardcodedStructs[i], ref deserializeFlags); break; } if (!isHardCoded) { // 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); while (true) { var tag = new UDefaultProperty(_Container, _Outer); if (tag.Deserialize()) { propertyValue += tag.Name + (tag.ArrayIndex > 0 && tag.Type != PropertyType.BoolProperty ? "[" + tag.ArrayIndex + "]" : String.Empty) + "=" + tag.DeserializeValue(deserializeFlags) + ","; } else { if (propertyValue.EndsWith(",")) { propertyValue = propertyValue.Remove(propertyValue.Length - 1, 1); } break; } } } propertyValue = propertyValue.Length != 0 ? "(" + propertyValue + ")" : "none"; break; } case PropertyType.ArrayProperty: { int arraySize = _Buffer.ReadIndex(); _Container.Record("arraySize", arraySize); if (arraySize == 0) { propertyValue = "none"; break; } // 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. var arrayType = PropertyType.None; var property = FindProperty(out _Outer) as UArrayProperty; if (property != null && property.InnerProperty != null) { 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 definined 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; } var sb = new StringBuilder(); sb.Append("("); for (int i = 0; i < arraySize; ++i) { sb.Append(DeserializeDefaultPropertyValue(arrayType, ref deserializeFlags) + (i != arraySize - 1 ? "," : String.Empty)); //propertyValue += DeserializeDefaultPropertyValue( arrayType, ref deserializeFlags ) // + (i != arraySize - 1 ? "," : String.Empty); } sb.Append(")"); propertyValue = sb.ToString(); //propertyValue = "(" + propertyValue + ")"; } else { var sb = new StringBuilder(); for (int i = 0; i < arraySize; ++i) { string elementValue = DeserializeDefaultPropertyValue(arrayType, ref deserializeFlags); if ((_TempFlags & ReplaceNameMarker) != 0) { sb.Append(elementValue.Replace("%ARRAYNAME%", Name + "(" + i + ")")); //propertyValue += elementValue.Replace( "%ARRAYNAME%", Name + "(" + i + ")" ); _TempFlags = 0x00; } else { sb.Append($"{Name}({i})={elementValue}"); //propertyValue += Name + "(" + i + ")=" + elementValue; } if (i != arraySize - 1) { sb.Append($"\r\n{UDecompilingState.Tabs}"); //propertyValue += "\r\n" + UDecompilingState.Tabs; } } propertyValue += sb.ToString(); } _TempFlags |= DoNotAppendName; break; } default: propertyValue = "/* Unknown default property type! */"; break; } } catch (Exception e) { return(propertyValue + "\r\n/* Exception thrown while deserializing " + Name + "\r\n" + e + " */"); } finally { _Outer = orgOuter; } return(propertyValue); }