public static PropertyCollection getDefaultStructValue(string className, bool stripTransients) { bool isImmutable = UnrealObjectInfo.IsImmutable(className, Mod.MEGame.ME2); if (Structs.ContainsKey(className)) { ClassInfo info = Structs[className]; try { PropertyCollection structProps = new PropertyCollection(); ClassInfo tempInfo = info; while (tempInfo != null) { foreach ((string propName, PropertyInfo propInfo) in tempInfo.properties) { if (stripTransients && propInfo.Transient) { continue; } if (getDefaultProperty(propName, propInfo, stripTransients, isImmutable) is UProperty uProp) { structProps.Add(uProp); } } if (!Structs.TryGetValue(tempInfo.baseClass, out tempInfo)) { tempInfo = null; } } structProps.Add(new NoneProperty()); string filepath = Path.Combine(ME2Directory.gamePath, "BioGame", info.pccPath); if (File.Exists(info.pccPath)) { filepath = info.pccPath; //Used for dynamic lookup } if (File.Exists(filepath)) { IMEPackage importPCC = MEPackageHandler.OpenMEPackage(filepath); var exportToRead = importPCC.getUExport(info.exportIndex); byte[] buff = exportToRead.Data.Skip(0x30).ToArray(); PropertyCollection defaults = PropertyCollection.ReadProps(exportToRead, new MemoryStream(buff), className); foreach (var prop in defaults) { structProps.TryReplaceProp(prop); } } return(structProps); } catch { return(null); } } return(null); }
public StructProperty(string structType, bool isImmutable, params UProperty[] props) : base(null) { StructType = structType; IsImmutable = isImmutable; PropType = PropertyType.StructProperty; Properties = new PropertyCollection(); foreach (var prop in props) { Properties.Add(prop); } }
public static PropertyCollection ReadSpecialStruct(IMEPackage pcc, MemoryStream stream, string structType, int size) { PropertyCollection props = new PropertyCollection(); if (pcc.Game == MEGame.ME3) { if (ME3UnrealObjectInfo.Structs.ContainsKey(structType)) { PropertyCollection defaultProps; //memoize if (defaultStructValues.ContainsKey(structType)) { defaultProps = defaultStructValues[structType]; } else { defaultProps = ME3UnrealObjectInfo.getDefaultStructValue(structType); if (defaultProps == null) { props.Add(new UnknownProperty(stream, size)); return(props); } defaultStructValues.Add(structType, defaultProps); } for (int i = 0; i < defaultProps.Count; i++) { UProperty uProperty = ReadSpecialStructProp(pcc, stream, defaultProps[i], structType); if (uProperty.PropType != PropertyType.None) { props.Add(uProperty); } } return(props); } } //TODO: implement getDefaultClassValue() for ME1 and ME2 so this isn't needed if (structType == "Rotator") { string[] labels = { "Pitch", "Yaw", "Roll" }; for (int i = 0; i < 3; i++) { props.Add(new IntProperty(stream, labels[i])); } } else if (structType == "Vector2d" || structType == "RwVector2") { string[] labels = { "X", "Y" }; for (int i = 0; i < 2; i++) { props.Add(new FloatProperty(stream, labels[i])); } } else if (structType == "Vector" || structType == "RwVector3") { string[] labels = { "X", "Y", "Z" }; for (int i = 0; i < 3; i++) { props.Add(new FloatProperty(stream, labels[i])); } } else if (structType == "Color") { string[] labels = { "B", "G", "R", "A" }; for (int i = 0; i < 4; i++) { props.Add(new ByteProperty(stream, labels[i])); } } else if (structType == "LinearColor") { string[] labels = { "R", "G", "B", "A" }; for (int i = 0; i < 4; i++) { props.Add(new FloatProperty(stream, labels[i])); } } //uses EndsWith to support RwQuat, RwVector4, and RwPlane else if (structType.EndsWith("Quat") || structType.EndsWith("Vector4") || structType.EndsWith("Plane")) { string[] labels = { "X", "Y", "Z", "W" }; for (int i = 0; i < 4; i++) { props.Add(new FloatProperty(stream, labels[i])); } } else if (structType == "TwoVectors") { string[] labels = { "X", "Y", "Z", "X", "Y", "Z" }; for (int i = 0; i < 6; i++) { props.Add(new FloatProperty(stream, labels[i])); } } else if (structType == "Matrix" || structType == "RwMatrix44") { string[] labels = { "X Plane", "Y Plane", "Z Plane", "W Plane" }; string[] labels2 = { "X", "Y", "Z", "W" }; for (int i = 0; i < 4; i++) { PropertyCollection structProps = new PropertyCollection(); for (int j = 0; j < 4; j++) { structProps.Add(new FloatProperty(stream, labels2[j])); } props.Add(new StructProperty("Plane", structProps, labels[i], true)); } } else if (structType == "Guid") { string[] labels = { "A", "B", "C", "D" }; for (int i = 0; i < 4; i++) { props.Add(new IntProperty(stream, labels[i])); } } else if (structType == "IntPoint") { string[] labels = { "X", "Y" }; for (int i = 0; i < 2; i++) { props.Add(new IntProperty(stream, labels[i])); } } else if (structType == "Box" || structType == "BioRwBox") { string[] labels = { "Min", "Max" }; string[] labels2 = { "X", "Y", "Z" }; for (int i = 0; i < 2; i++) { PropertyCollection structProps = new PropertyCollection(); for (int j = 0; j < 3; j++) { structProps.Add(new FloatProperty(stream, labels2[j])); } props.Add(new StructProperty("Vector", structProps, labels[i], true)); } props.Add(new ByteProperty(stream, "IsValid")); } else { props.Add(new UnknownProperty(stream, size)); } return(props); }
public static PropertyCollection ReadProps(IMEPackage pcc, MemoryStream stream, string typeName, bool includeNoneProperty = false) { //Uncomment this for debugging property engine /*DebugOutput.StartDebugger("Property Engine ReadProps() for "+typeName); * if (pcc.FileName == "C:\\Users\\Dev\\Downloads\\ME2_Placeables.upk") * { * //Debugger.Break(); * }*/ PropertyCollection props = new PropertyCollection(); long startPosition = stream.Position; while (stream.Position + 8 <= stream.Length) { int nameIdx = stream.ReadValueS32(); if (!pcc.isName(nameIdx)) { stream.Seek(-4, SeekOrigin.Current); break; } string name = pcc.getNameEntry(nameIdx); if (name == "None") { props.Add(new NoneProperty(stream, "None")); stream.Seek(4, SeekOrigin.Current); break; } NameReference nameRef = new NameReference { Name = name, Number = stream.ReadValueS32() }; int typeIdx = stream.ReadValueS32(); stream.Seek(4, SeekOrigin.Current); int size = stream.ReadValueS32(); if (!pcc.isName(typeIdx) || size < 0 || size > stream.Length - stream.Position) { stream.Seek(-16, SeekOrigin.Current); break; } stream.Seek(4, SeekOrigin.Current); PropertyType type; string namev = pcc.getNameEntry(typeIdx); if (Enum.IsDefined(typeof(PropertyType), namev)) { Enum.TryParse(namev, out type); } else { type = PropertyType.Unknown; } switch (type) { case PropertyType.StructProperty: string structType = pcc.getNameEntry(stream.ReadValueS32()); stream.Seek(4, SeekOrigin.Current); if (ME3UnrealObjectInfo.isImmutable(structType)) { PropertyCollection structProps = ReadSpecialStruct(pcc, stream, structType, size); var structprop = new StructProperty(structType, structProps, nameRef, true); structprop.Offset = stream.Position - 4; props.Add(structprop); } else { PropertyCollection structProps = ReadProps(pcc, stream, structType, includeNoneProperty); var structprop = new StructProperty(structType, structProps, nameRef); structprop.Offset = stream.Position - 4; props.Add(structprop); } break; case PropertyType.IntProperty: props.Add(new IntProperty(stream, nameRef)); break; case PropertyType.FloatProperty: props.Add(new FloatProperty(stream, nameRef)); break; case PropertyType.ObjectProperty: props.Add(new ObjectProperty(stream, nameRef)); break; case PropertyType.NameProperty: props.Add(new NameProperty(stream, pcc, nameRef)); break; case PropertyType.BoolProperty: props.Add(new BoolProperty(stream, pcc.Game, nameRef)); break; case PropertyType.BioMask4Property: props.Add(new BioMask4Property(stream, nameRef)); break; case PropertyType.ByteProperty: { if (size != 1) { NameReference enumType = new NameReference(); if (pcc.Game == MEGame.ME3) { enumType.Name = pcc.getNameEntry(stream.ReadValueS32()); enumType.Number = stream.ReadValueS32(); } else { enumType.Name = UnrealObjectInfo.GetEnumType(pcc.Game, name, typeName); } props.Add(new EnumProperty(stream, pcc, enumType, nameRef)); } else { if (pcc.Game == MEGame.ME3) { stream.Seek(8, SeekOrigin.Current); } props.Add(new ByteProperty(stream, nameRef)); } } break; case PropertyType.ArrayProperty: { props.Add(ReadArrayProperty(stream, pcc, typeName, nameRef)); } break; case PropertyType.StrProperty: { props.Add(new StrProperty(stream, nameRef)); } break; case PropertyType.StringRefProperty: props.Add(new StringRefProperty(stream, nameRef)); break; case PropertyType.DelegateProperty: props.Add(new DelegateProperty(stream, pcc, nameRef)); break; case PropertyType.Unknown: { props.Add(new UnknownProperty(stream, size, pcc.getNameEntry(typeIdx), nameRef)); } break; case PropertyType.None: if (includeNoneProperty) { props.Add(new NoneProperty(stream, "None")); } break; default: break; } } if (props.Count > 0) { //error reading props. if (props[props.Count - 1].PropType != PropertyType.None) { stream.Seek(startPosition, SeekOrigin.Begin); return(new PropertyCollection { endOffset = (int)stream.Position }); } //remove None Property if (!includeNoneProperty) { props.RemoveAt(props.Count - 1); } } props.endOffset = (int)stream.Position; return(props); }
public static PropertyCollection ReadProps(IMEPackage pcc, MemoryStream stream, string typeName) { PropertyCollection props = new PropertyCollection(); long startPosition = stream.Position; while (stream.Position + 8 <= stream.Length) { int nameIdx = stream.ReadValueS32(); if (!pcc.isName(nameIdx)) { stream.Seek(-4, SeekOrigin.Current); break; } string name = pcc.getNameEntry(nameIdx); if (name == "None") { props.Add(new NoneProperty { PropType = PropertyType.None }); stream.Seek(4, SeekOrigin.Current); break; } NameReference nameRef = new NameReference { Name = name, count = stream.ReadValueS32() }; int typeIdx = stream.ReadValueS32(); stream.Seek(4, SeekOrigin.Current); int size = stream.ReadValueS32(); if (!pcc.isName(typeIdx) || size < 0 || size > stream.Length - stream.Position) { stream.Seek(-16, SeekOrigin.Current); break; } stream.Seek(4, SeekOrigin.Current); PropertyType type; if (!Enum.TryParse(pcc.getNameEntry(typeIdx), out type)) { type = PropertyType.Unknown; } switch (type) { case PropertyType.StructProperty: string structType = pcc.getNameEntry(stream.ReadValueS32()); stream.Seek(4, SeekOrigin.Current); if (ME3UnrealObjectInfo.isImmutable(structType)) { PropertyCollection structProps = ReadSpecialStruct(pcc, stream, structType, size); props.Add(new StructProperty(structType, structProps, nameRef, true)); } else { PropertyCollection structProps = ReadProps(pcc, stream, structType); props.Add(new StructProperty(structType, structProps, nameRef)); } break; case PropertyType.IntProperty: props.Add(new IntProperty(stream, nameRef)); break; case PropertyType.FloatProperty: props.Add(new FloatProperty(stream, nameRef)); break; case PropertyType.ObjectProperty: props.Add(new ObjectProperty(stream, nameRef)); break; case PropertyType.NameProperty: props.Add(new NameProperty(stream, pcc, nameRef)); break; case PropertyType.BoolProperty: props.Add(new BoolProperty(stream, pcc.Game, nameRef)); break; case PropertyType.BioMask4Property: props.Add(new BioMask4Property(stream, nameRef)); break; case PropertyType.ByteProperty: { if (size != 1) { NameReference enumType = new NameReference(); if (pcc.Game == MEGame.ME3) { enumType.Name = pcc.getNameEntry(stream.ReadValueS32()); enumType.count = stream.ReadValueS32(); } else { enumType.Name = UnrealObjectInfo.GetEnumType(pcc.Game, name, typeName); } props.Add(new EnumProperty(stream, pcc, enumType, nameRef)); } else { if (pcc.Game == MEGame.ME3) { stream.Seek(8, SeekOrigin.Current); } props.Add(new ByteProperty(stream, nameRef)); } } break; case PropertyType.ArrayProperty: { props.Add(ReadArrayProperty(stream, pcc, typeName, nameRef)); } break; case PropertyType.StrProperty: { props.Add(new StrProperty(stream, nameRef)); } break; case PropertyType.StringRefProperty: props.Add(new StringRefProperty(stream, nameRef)); break; case PropertyType.DelegateProperty: props.Add(new DelegateProperty(stream, pcc, nameRef)); break; case PropertyType.Unknown: { props.Add(new UnknownProperty(stream, size, pcc.getNameEntry(typeIdx), nameRef)); } break; case PropertyType.None: default: break; } } if (props.Count > 0) { if (props[props.Count - 1].PropType != PropertyType.None) { stream.Seek(startPosition, SeekOrigin.Begin); return(new PropertyCollection { endOffset = (int)stream.Position }); } //remove None Property props.RemoveAt(props.Count - 1); } props.endOffset = (int)stream.Position; return(props); }