// Methods public override void Load(Stream fileStream, Dictionary <string, SetObjectType> objectTemplates) { // Header var reader = new BINAReader(fileStream); Header = reader.ReadHeader(); //Set Name (hardcoded to ASSUME it's four characters long) long namePosition = reader.BaseStream.Position; //Save position so we can jump back after reading name, type and parameters reader.JumpAhead(0xC); Name = reader.ReadNullTerminatedString(); reader.JumpTo(namePosition, true); reader.JumpAhead(0x2C); uint objectCount = reader.ReadUInt32(); uint objectTableOffset = reader.ReadUInt32(); uint groupCount = reader.ReadUInt32(); uint groupTableOffset = reader.ReadUInt32(); //Objects reader.JumpTo(objectTableOffset, false); for (uint i = 0; i < objectCount; i++) { var obj = new SetObject(); obj.ObjectID = i; uint objectNameOffset = reader.ReadUInt32(); uint objectTypeOffset = reader.ReadUInt32(); obj.UnknownBytes = reader.ReadBytes(16); //parameter.Unknown 16 bytes (pattern tends to be 40 00 00 00/01 (depending on whether object is activated by a group) 00 00 00 00 00 00 00 00 00 00 00 00) obj.Transform.Position = reader.ReadVector3(); obj.DrawDistance = reader.ReadSingle(); obj.Transform.Rotation = reader.ReadQuaternion(); uint parameterCount = reader.ReadUInt32(); uint parameterOffset = reader.ReadUInt32(); long position = reader.BaseStream.Position; //Save position so we can jump back after reading name, type and parameters //Object Name and Type reader.JumpTo(objectNameOffset, false); obj.ObjectName = reader.ReadNullTerminatedString(); reader.JumpTo(objectTypeOffset, false); obj.ObjectType = reader.ReadNullTerminatedString(); reader.JumpTo(parameterOffset, false); //Object Parameters for (uint c = 0; c < parameterCount; c++) { var parameter = new SetObjectParam(); uint parameterType = reader.ReadUInt32(); switch (parameterType) { case 0: //boolean parameter.DataType = typeof(bool); parameter.Data = reader.ReadUInt32() == 1; parameter.Unknown1 = reader.ReadUInt32(); parameter.Unknown2 = reader.ReadUInt32(); parameter.Unknown3 = reader.ReadUInt32(); break; case 1: //int parameter.DataType = typeof(int); parameter.Data = reader.ReadInt32(); parameter.Unknown1 = reader.ReadUInt32(); parameter.Unknown2 = reader.ReadUInt32(); parameter.Unknown3 = reader.ReadUInt32(); break; case 2: //single parameter.DataType = typeof(float); parameter.Data = reader.ReadSingle(); parameter.Unknown1 = reader.ReadUInt32(); parameter.Unknown2 = reader.ReadUInt32(); parameter.Unknown3 = reader.ReadUInt32(); break; case 3: //string uint offset = reader.ReadUInt32(); parameter.Unknown1 = reader.ReadUInt32(); parameter.Unknown2 = reader.ReadUInt32(); parameter.Unknown3 = reader.ReadUInt32(); long stringParameterPosition = reader.BaseStream.Position; //Save position so we can jump back after reading name, type and parameters reader.JumpTo(offset, false); parameter.DataType = typeof(string); parameter.Data = reader.ReadNullTerminatedString(); reader.JumpTo(stringParameterPosition, true); break; case 4: //Vector3 parameter.DataType = typeof(Vector3); parameter.Data = reader.ReadVector3(); parameter.Unknown3 = reader.ReadUInt32(); break; case 6: //uint parameter.DataType = typeof(uint); parameter.Data = reader.ReadUInt32(); parameter.Unknown1 = reader.ReadUInt32(); parameter.Unknown2 = reader.ReadUInt32(); parameter.Unknown3 = reader.ReadUInt32(); break; default: Console.WriteLine("Unhandled Data Type!"); break; } obj.Parameters.Add(parameter); } //Save Object and jump back for the next one Objects.Add(obj); reader.JumpTo(position, true); } //Groups reader.JumpTo(groupTableOffset, false); for (uint i = 0; i < groupCount; i++) { var group = new SetGroup(); uint groupNameOffset = reader.ReadUInt32(); uint groupTypeOffset = reader.ReadUInt32(); group.GroupObjectCount = reader.ReadUInt32(); uint groupObjectListOffset = reader.ReadUInt32(); long position = reader.BaseStream.Position; //Save position so we can jump back after reading name, type and object list //Group Name and Type reader.JumpTo(groupNameOffset, false); group.GroupName = reader.ReadNullTerminatedString(); reader.JumpTo(groupTypeOffset, false); group.GroupType = reader.ReadNullTerminatedString(); //Group Object List reader.JumpTo(groupObjectListOffset, false); for (uint c = 0; c < group.GroupObjectCount; c++) { reader.JumpAhead(4); group.ObjectIDs.Add(reader.ReadUInt32()); } //Save Group and jump back for the next one Groups.Add(group); reader.JumpTo(position, true); } }
public void ImportXML(Stream fileStream) { // Load XML and add loaded data to set data var xml = XDocument.Load(fileStream); Name = xml.Root.Attribute("name").Value; uint objID = 0; // For Object elements with no ID attribute. foreach (var objElem in xml.Root.Elements("Object")) { // Generate Object var typeAttr = objElem.Attribute("type"); var objIDAttr = objElem.Attribute("id"); var objNameAttr = objElem.Attribute("name"); if (typeAttr == null) { continue; } var obj = new SetObject() { ObjectType = typeAttr.Value, ObjectName = objNameAttr.Value, ObjectID = (objIDAttr == null) ? objID : Convert.ToUInt32(objIDAttr.Value), }; // Assign CustomData to Object var customDataElem = objElem.Element("CustomData"); if (customDataElem != null) { foreach (var customData in customDataElem.Elements()) { obj.CustomData.Add(customData.Name.LocalName, LoadParam(customData)); } } //Assign Draw Distance to Object var drawDistanceElem = objElem.Element("DrawDistance"); obj.DrawDistance = float.Parse(drawDistanceElem.Value); //Assign Unknown Bytes to object var unknownBytesElem = objElem.Element("UnknownBytes"); int byteNumber = 0; byte[] bytesXML = new byte[16]; foreach (var bytes in unknownBytesElem.Elements()) { bytesXML[byteNumber] = (byte)int.Parse(bytes.Value); byteNumber++; } obj.UnknownBytes = bytesXML; // Assign Parameters to Object var parametersElem = objElem.Element("Parameters"); if (parametersElem != null) { foreach (var paramElem in parametersElem.Elements()) { obj.Parameters.Add(LoadParam(paramElem)); } } // Assign Transforms to Object var transformsElem = objElem.Element("Transforms"); if (transformsElem != null) { var transforms = transformsElem.Elements("Transform"); int transformCount = transforms.Count(); if (transformCount > 0) { uint i = 0; obj.Children = new SetObjectTransform[transformCount - 1]; foreach (var transformElem in transforms) { var transform = LoadTransform(transformElem); if (i > 0) { obj.Children[i - 1] = transform; } else { obj.Transform = transform; } ++i; } } } ++objID; Objects.Add(obj); } foreach (var groupElm in xml.Root.Elements("Group")) { var groupNameElem = groupElm.Element("Name"); var groupObjectCountElem = groupElm.Element("ObjectCount"); var groupTypeElem = groupElm.Element("Type"); var group = new SetGroup() { GroupName = groupNameElem.Value, GroupObjectCount = uint.Parse(groupObjectCountElem.Value), GroupType = groupTypeElem.Value }; var objectsElem = groupElm.Element("ObjectIDs"); if (objectsElem != null) { foreach (var objectIDElem in objectsElem.Elements()) { group.ObjectIDs.Add(uint.Parse(objectIDElem.Value)); } } Groups.Add(group); } // Sub-Methods SetObjectParam LoadParam(XElement paramElem) { // Groups var dataTypeAttr = paramElem.Attribute("type"); if (dataTypeAttr == null) { var padAttr = paramElem.Attribute("padding"); uint?padding = null; if (uint.TryParse(padAttr?.Value, out var pad)) { padding = pad; } var group = new SetObjectParamGroup(padding); var parameters = group.Parameters; foreach (var param in paramElem.Elements()) { parameters.Add(LoadParam(param)); } return(group); } // Parameters var dataType = Types.GetTypeFromString(dataTypeAttr.Value); object data = null; if (dataType == typeof(Vector2)) { data = Helpers.XMLReadVector2(paramElem); } else if (dataType == typeof(Vector3)) { data = Helpers.XMLReadVector3(paramElem); } else if (dataType == typeof(Vector4)) { data = Helpers.XMLReadVector4(paramElem); } else if (dataType == typeof(Quaternion)) { data = Helpers.XMLReadQuat(paramElem); } else if (dataType == typeof(uint[])) { var countAttr = paramElem.Attribute("count"); uint arrLength = 0; if (countAttr != null) { uint.TryParse(countAttr.Value, out arrLength); } var values = paramElem.Value.Split(','); var arr = new uint[arrLength]; for (uint i = 0; i < arrLength; ++i) { if (i >= values.Length) { break; } uint.TryParse(values[i], out arr[i]); } data = arr; } else if (dataType == typeof(ForcesSetData.ObjectReference[])) { var countAttr = paramElem.Attribute("count"); uint arrLength = 0; if (countAttr != null) { uint.TryParse(countAttr.Value, out arrLength); } uint i = 0; var arr = new ForcesSetData.ObjectReference[arrLength]; foreach (var refElem in paramElem.Elements("ForcesObjectReference")) { var objRef = new ForcesSetData.ObjectReference(); objRef.ImportXML(refElem); arr[i] = objRef; ++i; } data = arr; } else if (dataType == typeof(ForcesSetData.ObjectReference)) { var objRef = new ForcesSetData.ObjectReference(); objRef.ImportXML(paramElem); data = objRef; } else { data = Convert.ChangeType(paramElem.Value, dataType); } return(new SetObjectParam(dataType, data)); } SetObjectTransform LoadTransform(XElement elem) { var posElem = elem.Element("Position"); var rotElem = elem.Element("Rotation"); var scaleElem = elem.Element("Scale"); return(new SetObjectTransform() { Position = Helpers.XMLReadVector3(posElem), Rotation = Helpers.XMLReadQuat(rotElem), Scale = Helpers.XMLReadVector3(scaleElem) }); } }