diff --git a/Mafia2Libs/ResourceTypes/FileTypes/Actors/Actor.cs b/Mafia2Libs/ResourceTypes/FileTypes/Actors/Actor.cs index d60aaa26..9f318406 100644 --- a/Mafia2Libs/ResourceTypes/FileTypes/Actors/Actor.cs +++ b/Mafia2Libs/ResourceTypes/FileTypes/Actors/Actor.cs @@ -12,27 +12,34 @@ public class Actor { List definitions; List items; - string pool; + + string bufferSize; + //temp_unk start int filesize; //size of sector in bits. After this integer (so filesize - 4) - short const6; //always 6 - short const2; //2 or 0 - byte[] unk02; //only full when const 2 == 0; + short version; //always 6, expected binary version + short flags; //2 is compressed, 0 is uncompressed + byte[] unk02; //only full when flags == 0; int const16; //always 16 int size; - int unk12; + int size1; int unk14; - int unk13; + int numEntityInitProps; List extraData; string fileName; - public List Definitions { + public List Definitions + { get { return definitions; } } - public List Items { + + public List Items + { get { return items; } } - public List ExtraData { + + public List ExtraData + { get { return extraData; } set { extraData = value; } } @@ -49,8 +56,8 @@ public Actor(string InFilename) : this() fileName = InFilename; const16 = 16; - const2 = 2; - const6 = 6; + flags = 2; + version = 6; } public Actor(FileInfo InFileInfo) @@ -64,7 +71,7 @@ public Actor(FileInfo InFileInfo) private string BuildDefinitions() { - if(Definitions.Count == 0) + if (Definitions.Count == 0) { // TODO: Check if this is correct? return string.Empty; @@ -132,6 +139,7 @@ private void Sanitize() items[i].DataID = reorganisedKeys[items[i].DataID]; } } + reorganisedKeys.Clear(); } @@ -166,7 +174,7 @@ public ActorDefinition CreateActorDefinition(ActorEntry entry) public void ReadFromFile(BinaryReader reader) { int poolLength = reader.ReadInt32(); - pool = new string(reader.ReadChars(poolLength)); + bufferSize = new string(reader.ReadChars(poolLength)); int hashesLength = reader.ReadInt32(); @@ -176,7 +184,7 @@ public void ReadFromFile(BinaryReader reader) { ActorDefinition definition = new ActorDefinition(reader); int pos = definition.NamePos; - definition.Name = pool.Substring(pos, pool.IndexOf('\0', pos) - pos); + definition.Name = bufferSize.Substring(pos, bufferSize.IndexOf('\0', pos) - pos); definitions.Add(definition); } @@ -184,26 +192,16 @@ public void ReadFromFile(BinaryReader reader) long actorDataOffset = reader.BaseStream.Position + 4; filesize = reader.ReadInt32(); - const6 = reader.ReadInt16(); - const2 = reader.ReadInt16(); + version = reader.ReadInt16(); + flags = reader.ReadInt16(); const16 = reader.ReadInt32(); - size = reader.ReadInt32(); //size of sector end. - unk12 = reader.ReadInt32(); - unk13 = reader.ReadInt32(); - //if (const2 != 2) - // throw new Exception("const_6 is not 6"); - - //if (const6 != 6) - // throw new Exception("const_2 is not 2"); - - //if (const16 != 16) - // throw new Exception("const_16 is not 16"); - - unk14 = reader.ReadInt32(); - - if (const2 == 2) + if (flags == 2) //compressed { + size = reader.ReadInt32(); //size of sector end. + size1 = reader.ReadInt32(); + numEntityInitProps = reader.ReadInt32(); + unk14 = reader.ReadInt32(); int newpos = (unk14 / 4 - 2) * 4; if (unk14 - 8 != newpos) { @@ -215,63 +213,97 @@ public void ReadFromFile(BinaryReader reader) extraData = new List(); for (int i = 0; i < count; i++) { - extraData.Add(new ActorExtraData(reader)); + extraData.Add(new ActorExtraData(reader, true)); } - } - else - { - unk02 = reader.ReadBytes(size - unk14); - } - int itemCount = reader.ReadInt32(); - reader.BaseStream.Seek(itemCount * 4, SeekOrigin.Current); + int itemCount = reader.ReadInt32(); + reader.BaseStream.Seek(itemCount * 4, SeekOrigin.Current); - items = new List(); - for (int i = 0; i != itemCount; i++) - { - ActorEntry item = new ActorEntry(reader); - if (item.DataID != -1) + items = new List(); + for (int i = 0; i != itemCount; i++) { - item.Data = ExtraData[item.DataID]; + ActorEntry item = new ActorEntry(reader, true); + if (item.DataID != -1) + { + item.Data = ExtraData[item.DataID]; + } + + items.Add(item); } - items.Add(item); - } + // Read how many cutscenes and check if we actually need to do anything. + int numCutscenes = reader.ReadInt32(); + if (numCutscenes > 0) + { + long endPosition = 0; + for (int i = 0; i < numCutscenes; i++) + { + // Get the offset, then save the position so we can return. + uint offset = reader.ReadUInt32(); + long currentPosition = reader.BaseStream.Position; + + // Seek to the offset and read cutscene name + reader.BaseStream.Seek(actorDataOffset + offset, SeekOrigin.Begin); + string cutsceneName = StringHelpers.ReadString(reader); + ushort cutscene_unk01 = reader.ReadUInt16(); + + // End position so we can make sure we have reached the end of file. + endPosition = reader.BaseStream.Position; + + // Return to our offset. + reader.BaseStream.Seek(currentPosition, SeekOrigin.Begin); + } + + // Seek back to our end point and assert if we have not reached the end of file. + reader.BaseStream.Position = endPosition; + } - // Read how many cutscenes and check if we actually need to do anything. - int numCutscenes = reader.ReadInt32(); - if (numCutscenes > 0) + ToolkitAssert.Ensure(reader.BaseStream.Position == reader.BaseStream.Length, + "This is not the end of the file. Message Greavesy with this message and the name of the SDS you tried to read."); + } + else //uncompressed { - long endPosition = 0; - for (int i = 0; i < numCutscenes; i++) + // Size could be offset item block + // Size1 could be offset to cutscenes + uint size = reader.ReadUInt32(); //only 39 so far + uint size1 = reader.ReadUInt32(); + + // Read all InitProps + uint numEntityInitProps = reader.ReadUInt32(); //only 1 so far + extraData = new List(); + for (int i = 0; i < numEntityInitProps; i++) { - // Get the offset, then save the position so we can return. - uint offset = reader.ReadUInt32(); - long currentPosition = reader.BaseStream.Position; + extraData.Add(new ActorExtraData(reader, false)); + } - // Seek to the offset and read cutscene name - reader.BaseStream.Seek(actorDataOffset + offset, SeekOrigin.Begin); - string cutsceneName = StringHelpers.ReadString(reader); - ushort cutscene_unk01 = reader.ReadUInt16(); + // Read all items + int itemCount = reader.ReadInt32(); + reader.BaseStream.Seek(itemCount * 4, SeekOrigin.Current); - // End position so we can make sure we have reached the end of file. - endPosition = reader.BaseStream.Position; + items = new List(); + + for (int i = 0; i != itemCount; i++) + { + ActorEntry item = new ActorEntry(reader, false); + if (item.DataID != -1) + { + item.Data = ExtraData[item.DataID]; + } - // Return to our offset. - reader.BaseStream.Seek(currentPosition, SeekOrigin.Begin); + items.Add(item); } - // Seek back to our end point and assert if we have not reached the end of file. - reader.BaseStream.Position = endPosition; + int numCutscenes = reader.ReadInt32();//until we find uncompressed cutscenes here + long endPosition = reader.BaseStream.Position; + ToolkitAssert.Ensure(reader.BaseStream.Position == reader.BaseStream.Length, + "This is not the end of the file. Message Greavesy with this message and the name of the SDS you tried to read."); } - - ToolkitAssert.Ensure(reader.BaseStream.Position == reader.BaseStream.Length, "This is not the end of the file. Message Greavesy with this message and the name of the SDS you tried to read."); } public void WriteToFile() { Sanitize(); - pool = BuildDefinitions(); + bufferSize = BuildDefinitions(); // Write the file using (BinaryWriter writer = new BinaryWriter(File.Open(fileName, FileMode.Create))) @@ -288,10 +320,10 @@ public void WriteToFile(BinaryWriter writer) List cutsceneEntries = new List(); Sanitize(); - pool = BuildDefinitions(); + bufferSize = BuildDefinitions(); - writer.Write(pool.Length); - StringHelpers.WriteString(writer, pool, false); + writer.Write(bufferSize.Length); + StringHelpers.WriteString(writer, bufferSize, false); writer.Write(definitions.Count); for (int i = 0; i < definitions.Count; i++) { @@ -300,8 +332,8 @@ public void WriteToFile(BinaryWriter writer) long instancePos = writer.BaseStream.Position; writer.Write(0); - writer.Write(const6); - writer.Write(const2); + writer.Write(version); + writer.Write(flags); writer.Write(const16); writer.Write(int.MinValue); //size writer.Write(int.MinValue); //unk12 @@ -313,10 +345,12 @@ public void WriteToFile(BinaryWriter writer) for (int i = 0; i < extraData.Count; i++) { writer.Write(instanceOffset); - instanceOffset += (extraData[i].Data != null ? extraData[i].Data.GetSize() : extraData[i].GetDataInBytes().Length) + 8; + instanceOffset += (extraData[i].Data != null + ? extraData[i].Data.GetSize() + : extraData[i].GetDataInBytes().Length) + 8; } - for(int i = 0; i < extraData.Count; i++) + for (int i = 0; i < extraData.Count; i++) { extraData[i].WriteToFile(writer); } @@ -324,7 +358,7 @@ public void WriteToFile(BinaryWriter writer) int itemOffset = instanceOffset + (items.Count * sizeof(int)) + 16; long itemPos = writer.BaseStream.Position; writer.Write(items.Count); - for(int i = 0; i < items.Count; i++) + for (int i = 0; i < items.Count; i++) { writer.Write(itemOffset); itemOffset += items[i].CalculateSize(); @@ -377,15 +411,15 @@ public void WriteToFile(BinaryWriter writer) } //for that unknown value. - long endPos = cutsceneEntryOffset - instancePos-4; - long instanceLength = writer.BaseStream.Position - instancePos-4; + long endPos = cutsceneEntryOffset - instancePos - 4; + long instanceLength = writer.BaseStream.Position - instancePos - 4; long unk = writer.BaseStream.Position - itemPos; long size = instanceLength - unk; writer.BaseStream.Seek(instancePos, SeekOrigin.Begin); writer.Write((int)(instanceLength)); - writer.Write(const6); - writer.Write(const2); + writer.Write(version); + writer.Write(flags); writer.Write(const16); writer.Write((int)size); //size writer.Write((int)(endPos)); //unk12 @@ -397,4 +431,4 @@ public static bool RequiresExtraData(ActorTypes InActorType) return (InActorType != ActorTypes.C_Car && InActorType != ActorTypes.C_Train); } } -} +} \ No newline at end of file diff --git a/Mafia2Libs/ResourceTypes/FileTypes/Actors/ActorEntry.cs b/Mafia2Libs/ResourceTypes/FileTypes/Actors/ActorEntry.cs index e86c259e..754164d5 100644 --- a/Mafia2Libs/ResourceTypes/FileTypes/Actors/ActorEntry.cs +++ b/Mafia2Libs/ResourceTypes/FileTypes/Actors/ActorEntry.cs @@ -1,8 +1,10 @@ using Gibbed.Illusion.FileFormats.Hashing; using System.ComponentModel; using System; +using System.Collections.Generic; using System.IO; using System.Numerics; +using System.Text; using Utils.StringHelpers; using Utils.VorticeUtils; @@ -14,8 +16,8 @@ public class ActorEntry int size; //item size in bytes; string actorTypeName; //actor type (string) string entityName; //entity name - string unkString; - string unk2String; + string unkString; //Name1 + string unk2String; //SceneSectorName string definitionName; //actor name string frameName; //frame name int actortypeID; @@ -28,78 +30,111 @@ public class ActorEntry short dataID; ActorExtraData data; - public int Size { + public int Size + { get { return size; } } - public string EntityName { + + public string EntityName + { get { return entityName; } - set { + set + { entityName = value; entityHash = FNV64.Hash(value); } } - public string ActorTypeName { + + public string ActorTypeName + { get { return actorTypeName; } set { actorTypeName = value; } } - public string UnkString { + + public string Name1 + { get { return unkString; } set { unkString = value; } } - public string Unk2String { + + public string SceneSectorName + { get { return unk2String; } set { unk2String = value; } } - public string DefinitionName { + + public string DefinitionName + { get { return definitionName; } set { definitionName = value; } } - public string FrameName { + + public string FrameName + { get { return frameName; } - set { + set + { frameName = value; frameNameHash = FNV64.Hash(value); } } - public int ActorTypeID { + + public int ActorTypeID + { get { return actortypeID; } set { actortypeID = value; } } - public ulong EntityHash { + + public ulong EntityHash + { get { return entityHash; } set { entityHash = value; } } - public ulong FrameNameHash { + + public ulong FrameNameHash + { get { return frameNameHash; } set { frameNameHash = value; } } - public Vector3 Position { + + public Vector3 Position + { get { return position; } set { position = value; } } - public Quaternion Rotation { + + public Quaternion Rotation + { get { return rotation; } set { rotation = value; } } - public Vector3 Scale { + + public Vector3 Scale + { get { return scale; } set { scale = value; } } - public bool bActivateOnInit { + + public bool bActivateOnInit + { get { return ActivateOnInit; } set { ActivateOnInit = value; } } - public short DataID { + + public short DataID + { get { return dataID; } set { dataID = value; } } [TypeConverter(typeof(ExpandableObjectConverter))] - public ActorExtraData Data { + public ActorExtraData Data + { get { return data; } set { data = value; } } + public ActorEntry() { rotation = Quaternion.Identity; @@ -112,9 +147,16 @@ public ActorEntry() definitionName = ""; } - public ActorEntry(BinaryReader reader) + public ActorEntry(BinaryReader reader, bool compressed) { - ReadFromFile(reader); + if (compressed) + { + ReadFromFile(reader); + } + else + { + ReadFromUncompressedFile(reader); + } } public void ReadFromFile(BinaryReader reader) @@ -136,6 +178,67 @@ public void ReadFromFile(BinaryReader reader) dataID = reader.ReadInt16(); } + public void ReadFromUncompressedFile(BinaryReader reader) + { + long initPos = reader.BaseStream.Position; + size = reader.ReadInt32(); + byte[] actorBytes = reader.ReadBytes((int)size); + + using (MemoryStream memoryStream = new MemoryStream(actorBytes)) //poor way of reading and parsing strings + { + string[] parts = new string[6]; // 6 should be maximum number of whole strings + int partIndex = 0; + + while (partIndex < parts.Length) + { + // reading array until it hits zero byte for splitting + List byteList = new List(); + int b; + while ((b = memoryStream.ReadByte()) != 0 && b != -1) + { + byteList.Add((byte)b); + } + + if (byteList.Count == 0 && b == -1) + { + // end of stream + break; + } + + parts[partIndex] = Encoding.UTF8.GetString(byteList.ToArray()); + partIndex++; + } + + actorTypeName = parts.Length > 0 ? parts[0] : ""; + entityName = parts.Length > 1 ? parts[1] : ""; + unkString = parts.Length > 2 ? parts[2] : ""; + unk2String = parts.Length > 3 ? parts[3] : ""; + definitionName = parts.Length > 4 ? parts[4] : ""; + frameName = parts.Length > 5 ? parts[5] : ""; + // sets reader position to the end of string array + + reader.BaseStream.Seek(initPos + memoryStream.Position + 4, SeekOrigin.Begin); //+4 because reading size + } + + position = Vector3Utils.ReadFromFile(reader); + rotation = QuaternionExtensions.ReadFromFile(reader); + scale = Vector3Utils.ReadFromFile(reader); + ActivateOnInit = Convert.ToBoolean(reader.ReadUInt16()); + dataID = reader.ReadInt16(); + + if (actorTypeName.Equals("FrameWrapper")) //didn't encounter any other type in uncompressed yet + { + actortypeID = 55; + } + //entityHash = reader.ReadUInt64(); + //isnt in uncompressed? + + //frameNameHash = reader.ReadUInt64(); + //TODO load matching framehash as in definition? + + reader.BaseStream.Seek(initPos + size, SeekOrigin.Begin);//moving onto next item or the end of stream + } + public int CalculateSize() { size = 4; @@ -193,4 +296,4 @@ public override string ToString() return string.Format("{0}, {1}, {2}, {3}", entityName, actortypeID, actorTypeName, dataID); } } -} +} \ No newline at end of file diff --git a/Mafia2Libs/ResourceTypes/FileTypes/Actors/ActorExtraData.cs b/Mafia2Libs/ResourceTypes/FileTypes/Actors/ActorExtraData.cs index af8ea7f4..3ed52c69 100644 --- a/Mafia2Libs/ResourceTypes/FileTypes/Actors/ActorExtraData.cs +++ b/Mafia2Libs/ResourceTypes/FileTypes/Actors/ActorExtraData.cs @@ -1,6 +1,7 @@ using System.ComponentModel; using System.Diagnostics; using System.IO; +using Utils.Extensions; using Utils.Logging; namespace ResourceTypes.Actors @@ -11,28 +12,36 @@ public class ActorExtraData IActorExtraDataInterface data; byte[] buffer; - public ActorTypes BufferType { + public ActorTypes BufferType + { get { return bufferType; } set { bufferType = value; } } [TypeConverter(typeof(ExpandableObjectConverter))] - public IActorExtraDataInterface Data { + public IActorExtraDataInterface Data + { get { return data; } set { data = value; } } public ActorExtraData() { - } - public ActorExtraData(BinaryReader reader) + public ActorExtraData(BinaryReader reader, bool compressed) { buffer = null; data = null; bufferType = 0; - ReadFromFile(reader); + if (compressed) + { + ReadFromFile(reader); + } + else + { + ReadFromUncompressedFile(reader); + } } public void ReadFromFile(BinaryReader reader) @@ -48,11 +57,40 @@ public void ReadFromFile(BinaryReader reader) { bool isBigEndian = false; //we'll change this once console parsing is complete. data = ActorFactory.LoadExtraData(bufferType, stream, isBigEndian); - ToolkitAssert.Ensure(bufferLength == stream.Length, string.Format("We did not reach the end of this stream! BufferType {0}", bufferType)); + ToolkitAssert.Ensure(bufferLength == stream.Length, + string.Format("We did not reach the end of this stream! BufferType {0}", bufferType)); + } + + buffer = (data == null ? buffer : null); + } + + public void ReadFromUncompressedFile(BinaryReader reader) + { + buffer = null; + data = null; + + bufferType = (ActorTypes)reader.ReadInt32(); //string will determine id, also this doesnt determine buffertype? + + uint bufferLength = 15; //todo fix the code for uncompressed if broken anywhere, is always 15? + buffer = reader.ReadBytes(15); + MemoryStream memoryStream = new MemoryStream(buffer); + string check = memoryStream.ReadStringBuffer(15); + if (check.Equals("FrameWrapper")) //didn't encounter any other type in uncompressed yet + { + bufferType = (ActorTypes)55; + } + + using (MemoryStream stream = new MemoryStream(buffer)) + { + bool isBigEndian = false; //we'll change this once console parsing is complete. + data = ActorFactory.LoadExtraData(bufferType, stream, isBigEndian); + ToolkitAssert.Ensure(bufferLength == stream.Length, + string.Format("We did not reach the end of this stream! BufferType {0}", bufferType)); } buffer = (data == null ? buffer : null); } + public void WriteToFile(BinaryWriter writer) { bool isBigEndian = false; @@ -70,7 +108,8 @@ public void WriteToFile(BinaryWriter writer) using (MemoryStream stream = new MemoryStream()) { data.WriteToFile(stream, isBigEndian); - ToolkitAssert.Ensure(data.GetSize() == stream.Length, string.Format("We did not reach the end of this stream! BufferType {0}", bufferType)); + ToolkitAssert.Ensure(data.GetSize() == stream.Length, + string.Format("We did not reach the end of this stream! BufferType {0}", bufferType)); stream.WriteTo(writer.BaseStream); } } @@ -100,4 +139,4 @@ public override string ToString() return string.Format("{0}", bufferType); } } -} +} \ No newline at end of file