protected MiloObjectDirEntry ParseWorldDir(AwesomeReader ar, MiloObjectDir dir)
        {
            // Read past unknown stuff, big hack
            int    unk1 = ar.ReadInt32();
            int    unk2 = ar.ReadInt32();
            float  unk3 = ar.ReadSingle();
            string unk4 = ar.ReadString();
            int    unk5 = ar.ReadInt32();
            int    unk6 = ar.ReadInt32();

            // Hack for project 9
            var dirEntry = new MiloObjectDirEntry()
            {
                Name = dir.Name
            };

            dirEntry.Version     = ar.ReadInt32();
            dirEntry.SubVersion  = ar.ReadInt32();
            dirEntry.ProjectName = ar.ReadString();

            // Skip matrices + constants
            var matCount = ar.ReadInt32(); // Usually 7

            ar.BaseStream.Position += (matCount * 48) + 9;

            // Read imported milos
            var importedMiloCount = ar.ReadInt32();

            dirEntry.ImportedMiloPaths = Enumerable.Range(0, importedMiloCount)
                                         .Select(x => ar.ReadString())
                                         .ToArray();

            // Boolean, true when sub directory?
            ar.ReadBoolean();

            // Sub directory names seem to be in reverse order of serialization...
            var subDirCount = ar.ReadInt32();
            var subDirNames = Enumerable.Range(0, subDirCount)
                              .Select(x => ar.ReadString())
                              .ToArray();

            // Read subdirectories
            foreach (var _ in subDirNames.Reverse())
            {
                var subDir = new MiloObjectDir();
                ReadFromStream(ar, subDir);

                dirEntry.SubDirectories.Add(subDir);
            }

            ar.BaseStream.Position += 17; // 0'd data + ADDE
            return(dirEntry);
        }
        public override void ReadFromStream(AwesomeReader ar, ISerializable data)
        {
            var    dir = data as MiloObjectDir;
            int    version = ReadMagic(ar, data);
            string dirType = null, dirName = null;

            dir.Extras.Clear(); // Clears for good measure

            if (version >= 24)
            {
                // Parses directory type/name
                dirType = ar.ReadString();
                dirName = FileHelper.SanitizePath(ar.ReadString());

                //ar.BaseStream.Position += 8; // Skips string count + total length
                dir.Extras.Add("Num1", ar.ReadInt32());
                dir.Extras.Add("Num2", ar.ReadInt32());
            }

            int entryCount = ar.ReadInt32();
            var entries    = Enumerable.Range(0, entryCount).Select(x => new
            {
                Type = ar.ReadString(),
                Name = FileHelper.SanitizePath(ar.ReadString())
            }).ToArray();

            if (version == 10)
            {
                // Parses external resource paths?
                entryCount = ar.ReadInt32();

                // Note: Entry can be empty
                var external = Enumerable.Range(0, entryCount)
                               .Select(x => ar.ReadString())
                               .ToList();

                dir.Extras.Add("ExternalResources", external);
            }
            else if (version == 25 && dirType == "ObjectDir")
            {
                // Hack for project 9
                var dirEntry = new MiloObjectDirEntry()
                {
                    Name = dirName
                };
                dirEntry.Version     = ar.ReadInt32();
                dirEntry.SubVersion  = ar.ReadInt32();
                dirEntry.ProjectName = ar.ReadString();

                // Skip matrices + constants
                var matCount = ar.ReadInt32(); // Usually 7
                ar.BaseStream.Position += (matCount * 48) + 9;

                // Read imported milos
                var importedMiloCount = ar.ReadInt32();
                dirEntry.ImportedMiloPaths = Enumerable.Range(0, importedMiloCount)
                                             .Select(x => ar.ReadString())
                                             .ToArray();

                // Boolean, true when sub directory?
                ar.ReadBoolean();

                // Sub directory names seem to be in reverse order of serialization...
                var subDirCount = ar.ReadInt32();
                var subDirNames = Enumerable.Range(0, subDirCount)
                                  .Select(x => ar.ReadString())
                                  .ToArray();

                // Read subdirectories
                foreach (var _ in subDirNames.Reverse())
                {
                    var subDir = new MiloObjectDir();
                    ReadFromStream(ar, subDir);

                    dirEntry.SubDirectories.Add(subDir);
                }

                dir.Extras.Add("DirectoryEntry", dirEntry);
                ar.BaseStream.Position += 17; // 0'd data + ADDE
            }
            else if (version == 25 && (dirType == "WorldDir"))
            {
                // Read past unknown stuff, big hack
                int    unk1 = ar.ReadInt32();
                int    unk2 = ar.ReadInt32();
                float  unk3 = ar.ReadSingle();
                string unk4 = ar.ReadString();
                int    unk5 = ar.ReadInt32();
                int    unk6 = ar.ReadInt32();

                // Hack for project 9
                var dirEntry = new MiloObjectDirEntry()
                {
                    Name = dirName
                };
                dirEntry.Version     = ar.ReadInt32();
                dirEntry.SubVersion  = ar.ReadInt32();
                dirEntry.ProjectName = ar.ReadString();

                // Skip matrices + constants
                var matCount = ar.ReadInt32(); // Usually 7
                ar.BaseStream.Position += (matCount * 48) + 9;

                // Read imported milos
                var importedMiloCount = ar.ReadInt32();
                dirEntry.ImportedMiloPaths = Enumerable.Range(0, importedMiloCount)
                                             .Select(x => ar.ReadString())
                                             .ToArray();

                // Boolean, true when sub directory?
                ar.ReadBoolean();

                // Sub directory names seem to be in reverse order of serialization...
                var subDirCount = ar.ReadInt32();
                var subDirNames = Enumerable.Range(0, subDirCount)
                                  .Select(x => ar.ReadString())
                                  .ToArray();

                // Read subdirectories
                foreach (var _ in subDirNames.Reverse())
                {
                    var subDir = new MiloObjectDir();
                    ReadFromStream(ar, subDir);

                    dirEntry.SubDirectories.Add(subDir);
                }

                dir.Extras.Add("DirectoryEntry", dirEntry);
                ar.BaseStream.Position += 17; // 0'd data + ADDE
            }
            else if (version == 25 && (dirType == "RndDir" || dirType == "SynthDir"))
            {
                // Read past unknown stuff, big hack
                int unk1 = ar.ReadInt32();

                // Hack for project 9
                var dirEntry = new MiloObjectDirEntry()
                {
                    Name = dirName
                };
                dirEntry.Version     = ar.ReadInt32();
                dirEntry.SubVersion  = ar.ReadInt32();
                dirEntry.ProjectName = ar.ReadString();

                // Skip matrices + constants
                var matCount = ar.ReadInt32(); // Usually 7
                ar.BaseStream.Position += (matCount * 48) + 9;

                // Read imported milos
                var importedMiloCount = ar.ReadInt32();
                dirEntry.ImportedMiloPaths = Enumerable.Range(0, importedMiloCount)
                                             .Select(x => ar.ReadString())
                                             .ToArray();

                // Boolean, true when sub directory?
                ar.ReadBoolean();

                // Sub directory names seem to be in reverse order of serialization...
                var subDirCount = ar.ReadInt32();
                var subDirNames = Enumerable.Range(0, subDirCount)
                                  .Select(x => ar.ReadString())
                                  .ToArray();

                // Read subdirectories
                foreach (var _ in subDirNames.Reverse())
                {
                    var subDir = new MiloObjectDir();
                    ReadFromStream(ar, subDir);

                    dirEntry.SubDirectories.Add(subDir);
                }

                dir.Extras.Add("DirectoryEntry", dirEntry);
                ar.BaseStream.Position += 17; // 0'd data + ADDE
            }
            else if (version == 25 && (dirType == "PanelDir" || dirType == "VocalTrackDir" || dirType == "UILabelDir" || dirType == "UILabelDir" || dirType == "UIListDir" || dirType == "PitchArrowDir" || dirType == "Character"))
            {
                // Read past unknown stuff, big hack
                int unk1 = ar.ReadInt32();
                int unk2 = ar.ReadInt32();

                // Hack for project 9
                var dirEntry = new MiloObjectDirEntry()
                {
                    Name = dirName
                };
                dirEntry.Version     = ar.ReadInt32();
                dirEntry.SubVersion  = ar.ReadInt32();
                dirEntry.ProjectName = ar.ReadString();

                // Skip matrices + constants
                var matCount = ar.ReadInt32(); // Usually 7
                ar.BaseStream.Position += (matCount * 48) + 9;

                // Read imported milos
                var importedMiloCount = ar.ReadInt32();
                dirEntry.ImportedMiloPaths = Enumerable.Range(0, importedMiloCount)
                                             .Select(x => ar.ReadString())
                                             .ToArray();

                // Boolean, true when sub directory?
                ar.ReadBoolean();

                // Sub directory names seem to be in reverse order of serialization...
                var subDirCount = ar.ReadInt32();
                var subDirNames = Enumerable.Range(0, subDirCount)
                                  .Select(x => ar.ReadString())
                                  .ToArray();

                // Read subdirectories
                foreach (var _ in subDirNames.Reverse())
                {
                    var subDir = new MiloObjectDir();
                    ReadFromStream(ar, subDir);

                    dirEntry.SubDirectories.Add(subDir);
                }

                dir.Extras.Add("DirectoryEntry", dirEntry);
                ar.BaseStream.Position += 17; // 0'd data + ADDE
            }
            else if (version == 25 && (dirType == "BackgroundDir" || dirType == "WorldInstance"))
            {
                // Read past unknown stuff, big hack
                int unk1 = ar.ReadInt32();
                int unk2 = ar.ReadInt32();
                int unk3 = ar.ReadInt32();

                // Hack for project 9
                var dirEntry = new MiloObjectDirEntry()
                {
                    Name = dirName
                };
                dirEntry.Version     = ar.ReadInt32();
                dirEntry.SubVersion  = ar.ReadInt32();
                dirEntry.ProjectName = ar.ReadString();

                // Skip matrices + constants
                var matCount = ar.ReadInt32(); // Usually 7
                ar.BaseStream.Position += (matCount * 48) + 9;

                // Read imported milos
                var importedMiloCount = ar.ReadInt32();
                dirEntry.ImportedMiloPaths = Enumerable.Range(0, importedMiloCount)
                                             .Select(x => ar.ReadString())
                                             .ToArray();

                // Boolean, true when sub directory?
                ar.ReadBoolean();

                // Sub directory names seem to be in reverse order of serialization...
                var subDirCount = ar.ReadInt32();
                var subDirNames = Enumerable.Range(0, subDirCount)
                                  .Select(x => ar.ReadString())
                                  .ToArray();

                // Read subdirectories
                foreach (var _ in subDirNames.Reverse())
                {
                    var subDir = new MiloObjectDir();
                    ReadFromStream(ar, subDir);

                    dirEntry.SubDirectories.Add(subDir);
                }

                dir.Extras.Add("DirectoryEntry", dirEntry);
                ar.BaseStream.Position += 17; // 0'd data + ADDE
            }
            else if (version == 25 && (dirType == "TrackPanelDir" || dirType == "H2HTrackPanelDir"))
            {
                // Read past unknown stuff, big hack
                int unk1 = ar.ReadInt32();
                int unk2 = ar.ReadInt32();
                int unk3 = ar.ReadInt32();
                int unk4 = ar.ReadInt32();

                // Hack for project 9
                var dirEntry = new MiloObjectDirEntry()
                {
                    Name = dirName
                };
                dirEntry.Version     = ar.ReadInt32();
                dirEntry.SubVersion  = ar.ReadInt32();
                dirEntry.ProjectName = ar.ReadString();

                // Skip matrices + constants
                var matCount = ar.ReadInt32(); // Usually 7
                ar.BaseStream.Position += (matCount * 48) + 9;

                // Read imported milos
                var importedMiloCount = ar.ReadInt32();
                dirEntry.ImportedMiloPaths = Enumerable.Range(0, importedMiloCount)
                                             .Select(x => ar.ReadString())
                                             .ToArray();

                // Boolean, true when sub directory?
                ar.ReadBoolean();

                // Sub directory names seem to be in reverse order of serialization...
                var subDirCount = ar.ReadInt32();
                var subDirNames = Enumerable.Range(0, subDirCount)
                                  .Select(x => ar.ReadString())
                                  .ToArray();

                // Read subdirectories
                foreach (var _ in subDirNames.Reverse())
                {
                    var subDir = new MiloObjectDir();
                    ReadFromStream(ar, subDir);

                    dirEntry.SubDirectories.Add(subDir);
                }

                dir.Extras.Add("DirectoryEntry", dirEntry);
                ar.BaseStream.Position += 17; // 0'd data + ADDE
            }
            else if (version >= 24)
            {
                // GH2 and above

                // Reads data as a byte array
                var entrySize  = GuessEntrySize(ar);
                var entryBytes = new MiloObjectBytes(dirType)
                {
                    Name = dirName
                };
                entryBytes.Data = ar.ReadBytes((int)entrySize);

                dir.Extras.Add("DirectoryEntry", entryBytes);
                ar.BaseStream.Position += 4;
            }


            foreach (var entry in entries)
            {
                var entryOffset = ar.BaseStream.Position;
                // TODO: De-serialize entries

                //try
                //{
                //    var miloEntry = ReadFromStream(ar.BaseStream, entry.Type);
                //    miloEntry.Name = entry.Name;

                //    dir.Entries.Add(miloEntry);
                //    ar.BaseStream.Position += 4; // Skips padding
                //    continue;
                //}
                //catch (Exception ex)
                //{
                //    // Catch exception and log?
                //    ar.Basestream.Position = entryOffset; // Return to start
                //}

                // Reads data as a byte array
                var entrySize  = GuessEntrySize(ar);
                var entryBytes = new MiloObjectBytes(entry.Type)
                {
                    Name = entry.Name
                };
                entryBytes.Data = ar.ReadBytes((int)entrySize);

                dir.Entries.Add(entryBytes);
                ar.BaseStream.Position += 4;
            }
        }