public static StringTable FromStream(EndianBinaryReader stream) { StringTable newTable = new StringTable(); long headerStart = stream.BaseStream.Position; ushort stringCount = stream.ReadUInt16(); stream.ReadUInt16(); // Padding for (int i = 0; i < stringCount; i++) { // Jump us to the string 'header' by calculating 0x4 for for the StringTable header and then 0x4 for each string header. stream.BaseStream.Position = headerStart + ((i + 1) * 0x4); ushort stringHash = stream.ReadUInt16(); ushort stringOffset = stream.ReadUInt16(); // Jump forward to the offset to read the string. stream.BaseStream.Position = headerStart + stringOffset; string value = stream.ReadStringUntil('\0'); newTable.Strings.Add(new Entry(value, stringHash)); } return newTable; }
private RawMapEntity LoadMapEntityFromStream(string chunkFourCC, EndianBinaryReader reader, MapEntityDataDescriptor template) { RawMapEntity obj = new RawMapEntity(); obj.Fields = new PropertyCollection(); obj.FourCC = chunkFourCC; // We're going to examine the Template's properties and load based on the current template type. for (int i = 0; i < template.Fields.Count; i++) { var templateProperty = template.Fields[i]; string propertyName = templateProperty.FieldName; PropertyType type = templateProperty.FieldType; object value = null; switch (type) { case PropertyType.FixedLengthString: value = reader.ReadString(templateProperty.Length).Trim(new[] { '\0' }); break; case PropertyType.String: value = reader.ReadStringUntil('\0'); break; case PropertyType.Byte: value = reader.ReadByte(); break; case PropertyType.Short: value = reader.ReadInt16(); break; case PropertyType.Int32BitField: case PropertyType.Int32: value = reader.ReadInt32(); break; case PropertyType.Float: value = reader.ReadSingle(); break; case PropertyType.Vector3: value = new Vector3(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle()); break; case PropertyType.Vector2: value = new Vector2(reader.ReadSingle(), reader.ReadSingle()); break; case PropertyType.Enum: byte enumIndexBytes = reader.ReadByte(); // ToDo: Resolve to actual Enum later. value = enumIndexBytes; break; case PropertyType.ObjectReference: // When we first resolve them, we're going to keep the value as the reference byte, // and then when they are post-processed they'll be turned into a proper type. value = (int)reader.ReadByte(); break; case PropertyType.ObjectReferenceShort: // When we first resolve them, we're going to keep the value as the reference byte, // and then when they are post-processed they'll be turned into a proper type. value = (int)reader.ReadUInt16(); break; case PropertyType.ObjectReferenceArray: // When we first resolve them, we're going to keep the value as the reference byte, // and then when they are post-processed they'll be turned into a proper type. var refList = new BindingList<object>(); for (int refArray = 0; refArray < templateProperty.Length; refArray++) { refList.Add((int)reader.ReadByte()); } value = refList; break; case PropertyType.XYRotation: { Vector3 eulerAngles = new Vector3(); for (int f = 0; f < 2; f++) eulerAngles[f] = (reader.ReadInt16() * (180 / 32786f)); Quaternion xAxis = Quaternion.FromAxisAngle(new Vector3(1, 0, 0), eulerAngles.X * MathE.Deg2Rad); Quaternion yAxis = Quaternion.FromAxisAngle(new Vector3(0, 1, 0), eulerAngles.Y * MathE.Deg2Rad); // Swizzling to the ZYX order seems to be the right one. Quaternion finalRot = yAxis * xAxis; value = finalRot; } break; case PropertyType.XYZRotation: { Vector3 eulerAngles = new Vector3(); for (int f = 0; f < 3; f++) eulerAngles[f] = (reader.ReadInt16() * (180 / 32786f)); Quaternion xAxis = Quaternion.FromAxisAngle(new Vector3(1, 0, 0), eulerAngles.X * MathE.Deg2Rad); Quaternion yAxis = Quaternion.FromAxisAngle(new Vector3(0, 1, 0), eulerAngles.Y * MathE.Deg2Rad); Quaternion zAxis = Quaternion.FromAxisAngle(new Vector3(0, 0, 1), eulerAngles.Z * MathE.Deg2Rad); // Swizzling to the ZYX order seems to be the right one. Quaternion finalRot = zAxis * yAxis * xAxis; value = finalRot; } break; case PropertyType.YRotation: { float yRotation = reader.ReadInt16() * (180 / 32786f); Quaternion yAxis = Quaternion.FromAxisAngle(new Vector3(0, 1, 0), yRotation * MathE.Deg2Rad); value = yAxis; } break; case PropertyType.Color32: value = new Color32(reader.ReadByte(), reader.ReadByte(), reader.ReadByte(), reader.ReadByte()); break; case PropertyType.Color24: value = new Color24(reader.ReadByte(), reader.ReadByte(), reader.ReadByte()); break; case PropertyType.Vector3Byte: type = PropertyType.Vector3Byte; value = new Vector3(reader.ReadByte(), reader.ReadByte(), reader.ReadByte()); break; case PropertyType.Bits: value = (byte)reader.ReadBits(templateProperty.Length); break; } // This... this could get dicy. If the template we just read was a "Name" then we now have the technical name (and value) // of the object. We can then search for the MapObjectDataDescriptor that matches the technical name, and then edit the // remaining fields. However, this gets somewhat dicey, because we're modifying the length of the Fields array for templates // while iterating through it. However, the Name field always comes before any of the fields we'd want to modify, we're going to // do an in-place replacement of the fields (since Fields.Count will increase) and then we get free loading of the complex templates // without later post-processing them. if (templateProperty.FieldName == "Name") { // See if our template list has a complex version of this file, otherwise grab the default. MapObjectDataDescriptor complexDescriptor = m_editorCore.Templates.MapObjectDataDescriptors.Find(x => x.FourCC == chunkFourCC && x.TechnicalName == templateProperty.FieldName); if (complexDescriptor == null) complexDescriptor = m_editorCore.Templates.DefaultMapObjectDataDescriptor; // Determine which field we need to remove, and then insert in the other fields (in order) where it used to be. foreach (var fieldToReplace in complexDescriptor.DataOverrides) { for (int k = 0; k < template.Fields.Count; k++) { if (template.Fields[k].FieldName == fieldToReplace.ParameterName) { // Remove the old field. template.Fields.RemoveAt(k); // Now insert the new fields starting at the location of the one we just replaced. template.Fields.InsertRange(k, fieldToReplace.Values); break; } } } } Property instanceProp = new Property(templateProperty.FieldName, type, value); obj.Fields.Properties.Add(instanceProp); } return obj; }
void Read(EndianBinaryReader reader) { if (CurrentControl != null) { CurrentControl.Hide(); CurrentControl.RemoveFromMainForm(MainForm); CurrentControl = null; } Cam = new Camera(); ChunkTemplates = LoadTemplates(); Chunks.Clear(); int numChunkHeaders = reader.ReadInt32(); int readerOffsetStorage = 4; for (int i = 0; i < numChunkHeaders; i++) { string chunkName = reader.ReadStringUntil('\0'); reader.BaseStream.Position -= 1; int numChunks = reader.ReadInt32(); int chunksOffset = reader.ReadInt32(); readerOffsetStorage = (int)reader.BaseStream.Position; reader.BaseStream.Position = chunksOffset; if (chunkName == "RTBL") { //Skip offset bank, which is a table of integers reader.BaseStream.Position += 4 * numChunks; } for (int j = 0; j < numChunks; j++) { Chunk newChunk = new Chunk(); newChunk.Read(reader, chunkName, ChunkTemplates); Chunks.Add(newChunk); } reader.BaseStream.Position = readerOffsetStorage; } foreach (Chunk chunk in Chunks) { string chunkSearchString = chunk.ChunkType.Remove(chunk.ChunkType.Length - 1); EntityTemplate template = ChunkTemplates.Find(x => x.ChunkID.Contains(chunkSearchString)); template.ReadSpecialProcess(chunk.Fields, Chunks); } UpdateTreeView(); MainForm.ElementView.SelectedNode = MainForm.ElementView.Nodes[0]; SelectedChunk = Chunks[0]; Controls = LoadControls(); IsListLoaded = true; }