public override void WriteToStream(AwesomeWriter aw, ISerializable data) { var env = data as Environ; // TODO: Add version check var version = Magic(); aw.Write(version); MiloSerializer.WriteToStream(aw.BaseStream, env.Draw); // Write lights aw.Write((int)env.Lights.Count); env.Lights.ForEach(x => aw.Write((string)x)); // Write ambient color aw.Write((float)env.AmbientColor.R); aw.Write((float)env.AmbientColor.G); aw.Write((float)env.AmbientColor.B); aw.Write((float)env.AmbientColor.A); // Write fog info aw.Write((float)env.FogStart); aw.Write((float)env.FogEnd); aw.Write((float)env.FogColor.R); aw.Write((float)env.FogColor.G); aw.Write((float)env.FogColor.B); aw.Write((float)env.FogColor.A); aw.Write((bool)env.EnableFog); }
public override void WriteToStream(AwesomeWriter aw, ISerializable data) { var cam = data as Cam; // TODO: Add version check var version = Magic(); aw.Write(version); MiloSerializer.WriteToStream(aw.BaseStream, cam.Trans); MiloSerializer.WriteToStream(aw.BaseStream, cam.Draw); aw.Write((float)cam.NearPlane); aw.Write((float)cam.FarPlane); aw.Write((float)cam.FOV); // Write screen area aw.Write((float)cam.ScreenArea.X); aw.Write((float)cam.ScreenArea.Y); aw.Write((float)cam.ScreenArea.Width); aw.Write((float)cam.ScreenArea.Height); // Write z-range aw.Write((float)cam.ZRange.X); aw.Write((float)cam.ZRange.Y); aw.Write((string)cam.TargetTexture); }
public static byte[] WriteToBytes(this MiloSerializer serializer, ISerializable obj) { using (var ms = new MemoryStream()) { serializer.WriteToStream(ms, obj); return(ms.ToArray()); } }
public override void WriteToStream(AwesomeWriter aw, ISerializable data) { var view = data as View; // TODO: Add version check var version = Magic(); aw.Write(version); MiloSerializer.WriteToStream(aw.BaseStream, view.Anim); MiloSerializer.WriteToStream(aw.BaseStream, view.Trans); MiloSerializer.WriteToStream(aw.BaseStream, view.Draw); aw.Write((string)view.MainView); aw.Write((float)view.LODHeight); aw.Write((float)view.LODWidth); }
public override void WriteToStream(AwesomeWriter aw, ISerializable data) { var tex = data as Tex; // TODO: Add version check var version = Magic(); aw.Write((int)version); if (MiloSerializer.Info.Version >= 25) { aw.Write((int)1); // Definitely needed! } if (version >= 10) { aw.Write(new byte[9]); } aw.Write((int)tex.Width); aw.Write((int)tex.Height); aw.Write((int)tex.Bpp); aw.Write(tex.ExternalPath); aw.Write((float)tex.IndexF); aw.Write((int)tex.Index); aw.Write((bool)tex.UseExternal); if (tex.Bitmap != null) { MiloSerializer.WriteToStream(aw.BaseStream, tex.Bitmap); } /* * if (!tex.UseExternal && tex.Bitmap != null) * { * aw.Write(false); * MiloSerializer.WriteToStream(aw.BaseStream, tex.Bitmap); * } * else * { * aw.Write(true); * }*/ }
public override void WriteToStream(AwesomeWriter aw, ISerializable data) { var mesh = data as Mesh; // TODO: Add version check var version = Magic(); aw.Write(version); MiloSerializer.WriteToStream(aw.BaseStream, mesh.Trans); MiloSerializer.WriteToStream(aw.BaseStream, mesh.Draw); aw.Write((string)mesh.Material); aw.Write((string)mesh.MainMesh); aw.Write((int)mesh.Unknown); aw.Write((int)1); aw.Write((byte)0); // Write vertices aw.Write((int)mesh.Vertices.Count); mesh.Vertices.ForEach(x => { // TODO: Add switch statement for milo versions aw.Write((float)x.X); aw.Write((float)x.Y); aw.Write((float)x.Z); aw.Write((float)x.NormalX); aw.Write((float)x.NormalY); aw.Write((float)x.NormalZ); aw.Write((float)x.ColorR); aw.Write((float)x.ColorG); aw.Write((float)x.ColorB); aw.Write((float)x.ColorA); aw.Write((float)x.U); aw.Write((float)x.V); }); // Write faces aw.Write((int)mesh.Faces.Count); mesh.Faces.ForEach(x => { aw.Write((ushort)x.V1); aw.Write((ushort)x.V2); aw.Write((ushort)x.V3); }); // Write group sizes aw.Write((int)mesh.Groups.Count); mesh.Groups.ForEach(x => aw.Write((byte)x.Size)); const int boneCount = 4; // Always 4? var bones = mesh.Bones .Take(boneCount) .ToList(); // Write bones if (bones.Count > 0) { bones.ForEach(x => aw.Write((string)x.Name)); RepeatFor(boneCount - bones.Count, () => aw.Write((string)"")); bones.ForEach(x => WriteMatrix(x.Mat, aw)); RepeatFor(boneCount - bones.Count, () => WriteMatrix(Matrix4.Identity(), aw)); } else { aw.Write((int)0); } if (mesh.Groups.Sum(x => x.Sections.Count) == 0 && mesh.Groups.Sum(x => x.VertexIndicies.Count) == 0) { return; } // Write group sections + vertex indices mesh.Groups.ForEach(x => { aw.Write((int)x.Sections.Count); aw.Write((int)x.VertexIndicies.Count); x.Sections.ForEach(y => aw.Write((int)y)); x.VertexIndicies.ForEach(y => aw.Write((ushort)y)); }); }
public override void WriteToStream(AwesomeWriter aw, ISerializable data) { var dir = data as MiloObjectDir; aw.Write((int)Magic()); // Sort entries using sort order defined in games var sortedEntries = dir.Entries .OrderBy(x => GetEntryTypeSortValue(x.Type)) .ToList(); if (Magic() >= 24) { // Write extra info var dirEntry = dir.Extras["DirectoryEntry"] as MiloObject; aw.Write((string)dirEntry.Type); aw.Write((string)dirEntry.Name); // Calculate hash + blob sizes var hashCount = (sortedEntries.Count + 1) * 2; var blobSize = sortedEntries.Select(x => x.Name.Length + 1).Sum() + (dirEntry.Name.Length + 1); aw.Write((int)hashCount); aw.Write((int)blobSize); } // Write entries aw.Write((int)sortedEntries.Count); foreach (var entry in sortedEntries) { // Used to preserve file name var dirtyName = UnsanitizeFileName(entry.Name); aw.Write((string)entry.Type); aw.Write((string)dirtyName); } if (Magic() >= 24) { var dirEntryRaw = dir.Extras["DirectoryEntry"] as ISerializable; if (Magic() == 25 && dir.Type == "ObjectDir" && dirEntryRaw is MiloObjectDirEntry dirEntry) { // Hack for project 9 aw.Write((int)dirEntry.Version); aw.Write((int)dirEntry.SubVersion); aw.Write((string)dirEntry.ProjectName); // Write matrices aw.Write((int)7); foreach (var mat in Enumerable .Range(0, 7) .Select(x => Matrix4.Identity())) { aw.Write((float)mat.M11); aw.Write((float)mat.M12); aw.Write((float)mat.M13); aw.Write((float)mat.M21); aw.Write((float)mat.M22); aw.Write((float)mat.M23); aw.Write((float)mat.M31); aw.Write((float)mat.M32); aw.Write((float)mat.M33); aw.Write((float)mat.M41); aw.Write((float)mat.M42); aw.Write((float)mat.M43); } // Constants? I hope aw.Write((int)0); aw.Write((bool)true); aw.Write((int)0); // Write imported milo paths if (!(dirEntry.ImportedMiloPaths is null)) { aw.Write((int)dirEntry.ImportedMiloPaths.Length); foreach (var path in dirEntry.ImportedMiloPaths) { aw.Write((string)path); } } else { aw.Write((int)0); } // Might be different depending on dir being root/nested // Root: false, Nested: true aw.Write((bool)(dirEntry.SubDirectories.Count <= 0)); // TODO: Use a better way to determine if nested // Write sub directory names aw.Write((int)dirEntry.SubDirectories.Count); foreach (var subName in dirEntry .SubDirectories .Select(x => $"{x.Name}.milo") .Reverse()) // Seems to be reverse order of serialization { aw.Write((string)subName); } // Write sub directory data foreach (var subDir in dirEntry.SubDirectories) { WriteToStream(aw, subDir); } aw.BaseStream.Position += 13; // Zero'd bytes } else { MiloSerializer.WriteToStream(aw.BaseStream, dirEntryRaw); } aw.Write(ADDE_PADDING); }
public IActionResult TestSerialization([FromBody] ScanRequest request, bool testSerialize) { if (!Directory.Exists(request.InputPath)) { return(BadRequest($"Directory \"{request.InputPath}\" does not exist!")); } var miloEntryRegex = new Regex(@"([^\\]*([.](rnd)|(gh)))\\([^\\]+)\\([^\\]+)$", RegexOptions.IgnoreCase); var miloEntries = Directory.GetFiles(request.InputPath, "*", SearchOption.AllDirectories) .Where(x => miloEntryRegex.IsMatch(x)) .Select(y => { var match = miloEntryRegex.Match(y); var miloArchive = match.Groups[1].Value; var miloEntryType = match.Groups[5].Value; var miloEntryName = match.Groups[6].Value; return(new { FullPath = y, MiloArchive = miloArchive, MiloEntryType = miloEntryType, MiloEntryName = miloEntryName }); }) .ToArray(); //var groupedEntries = miloEntries.GroupBy(x => x.MiloEntryType).ToDictionary(g => g.Key, g => g.ToList()); MiloSerializer serializer = new MiloSerializer(new SystemInfo() { Version = 10, Platform = Platform.PS2, BigEndian = false }); var supportedTypes = new [] { "Cam", "Environ", "Mat", "Mesh", "Tex", "View" }; var results = miloEntries .Where(w => supportedTypes.Contains(w.MiloEntryType)) .OrderBy(x => x.MiloEntryType) .ThenBy(y => y.FullPath) .Select(z => { ISerializable data = null; string message = ""; bool converted = false; bool perfectSerialize = true; try { switch (z.MiloEntryType) { case "Cam": data = serializer.ReadFromFile <Cam>(z.FullPath); break; case "Environ": data = serializer.ReadFromFile <Environ>(z.FullPath); break; case "Mat": data = serializer.ReadFromFile <Mat>(z.FullPath); break; case "Mesh": data = serializer.ReadFromFile <Mesh>(z.FullPath); break; case "Tex": data = serializer.ReadFromFile <Tex>(z.FullPath); break; case "View": data = serializer.ReadFromFile <View>(z.FullPath); break; default: throw new Exception("Not Supported"); } (data as IMiloObject).Name = z.MiloEntryName; converted = true; } catch (Exception ex) { var trace = new StackTrace(ex, true); var frame = trace.GetFrame(0); var name = frame.GetMethod().ReflectedType.Name; message = $"{name}: {ex.Message}"; } if (testSerialize) { try { byte[] bytes; using (var ms = new MemoryStream()) { serializer.WriteToStream(ms, data); bytes = ms.ToArray(); } var origBytes = System.IO.File.ReadAllBytes(z.FullPath); if (bytes.Length != origBytes.Length) { throw new Exception("Byte count doesn't match"); } for (int i = 0; i < bytes.Length; i++) { if (bytes[i] != origBytes[i]) { throw new Exception("Bytes don't match"); } } } catch (Exception ex) { perfectSerialize = false; } } return(new { Entry = z, Data = data, Message = message, Converted = converted, Serialized = perfectSerialize }); }).ToList(); /* * var textures = groupedEntries["Tex"] * .Select(x => serializer.ReadFromFile<Tex>(x.FullPath)) * .ToList(); * * var views = groupedEntries["View"] * .Select(x => serializer.ReadFromFile<View>(x.FullPath)) * .ToList(); * * var meshes = groupedEntries["Mesh"] * .Select(x => serializer.ReadFromFile<Mesh>(x.FullPath)) * .ToList(); */ return(Ok(new { TotalCoverage = results.Count(x => x.Converted) / (double)results.Count, TotalScanned = results.Count, ByType = results .GroupBy(x => x.Entry.MiloEntryType) .ToDictionary(g => g.Key, g => new { Coverage = g.Count(x => x.Converted) / (double)g.Count(), Scanned = g.Count(), //Converted = g // .Where(x => x.Converted) // .Select(x => new // { // x.Entry.FullPath // }), NotConverted = g .Where(x => !x.Converted) .Select(x => new { x.Entry.FullPath, x.Message }) }), NotSerialized = results .Where(x => !x.Serialized) .Select(y => y.Entry.FullPath) //Converted = results // .Where(x => x.Converted) // .Select(x => new // { // x.Entry.FullPath // }), //NotConverted = results // .Where(x => !x.Converted) // .Select(x => new // { // x.Entry.FullPath, // x.Message // }) })); }
public override void WriteToStream(AwesomeWriter aw, ISerializable data) { var dir = data as MiloObjectDir; aw.Write((int)Magic()); if (Magic() >= 24) { // Write extra info var dirEntry = dir.Extras["DirectoryEntry"] as MiloObject; aw.Write((string)dirEntry.Type); aw.Write((string)dirEntry.Name); /* * var entryNameLengths = dir.Entries.Select(x => ((string)x.Name).Length).Sum(); * aw.Write(0); // Unknown * aw.Write(1 + ((string)dirEntry.Name).Length + dir.Entries.Count + entryNameLengths); */ if (dir.Extras.TryGetValue("Num1", out var num1)) { aw.Write((int)num1); } if (dir.Extras.TryGetValue("Num2", out var num2)) { aw.Write((int)num2); } aw.Write((int)dir.Entries.Count); } foreach (var entry in dir.Entries) { aw.Write((string)entry.Type); aw.Write((string)entry.Name); } if (Magic() >= 24) { var dirEntryRaw = dir.Extras["DirectoryEntry"] as ISerializable; if (Magic() == 25 && dir.Type == "ObjectDir" && dirEntryRaw is MiloObjectDirEntry dirEntry) { // Hack for project 9 aw.Write((int)dirEntry.Version); aw.Write((int)dirEntry.SubVersion); aw.Write((string)dirEntry.ProjectName); // Write matrices aw.Write((int)7); foreach (var mat in Enumerable .Range(0, 7) .Select(x => Matrix4.Identity())) { aw.Write((float)mat.M11); aw.Write((float)mat.M12); aw.Write((float)mat.M13); aw.Write((float)mat.M21); aw.Write((float)mat.M22); aw.Write((float)mat.M23); aw.Write((float)mat.M31); aw.Write((float)mat.M32); aw.Write((float)mat.M33); aw.Write((float)mat.M41); aw.Write((float)mat.M42); aw.Write((float)mat.M43); } // Constants? I hope aw.Write((int)0); aw.Write((bool)true); aw.Write((int)0); // Write imported milo paths if (!(dirEntry.ImportedMiloPaths is null)) { aw.Write((int)dirEntry.ImportedMiloPaths.Length); foreach (var path in dirEntry.ImportedMiloPaths) { aw.Write((string)path); } } else { aw.Write((int)0); } // Might be different depending on dir being root/nested // Root: false, Nested: true aw.Write((bool)(dirEntry.SubDirectories.Count <= 0)); // TODO: Use a better way to determine if nested // Write sub directory names aw.Write((int)dirEntry.SubDirectories.Count); foreach (var subName in dirEntry .SubDirectories .Select(x => $"{x.Name}.milo") .Reverse()) // Seems to be reverse order of serialization { aw.Write((string)subName); } // Write sub directory data foreach (var subDir in dirEntry.SubDirectories) { WriteToStream(aw, subDir); } aw.BaseStream.Position += 13; // Zero'd bytes } else { MiloSerializer.WriteToStream(aw.BaseStream, dirEntryRaw); } aw.Write(ADDE_PADDING); }