public static void CollDataToSVG(string filename, SBM_Coll_Data colldata) { svg svg = new svg(); var groups = new List <svgShape>(); foreach (var area in colldata.LineGroups) { svgGroup g = new svgGroup(); List <svgShape> lines = new List <svgShape>(); lines.AddRange(AreaToList(colldata, area.TopLineIndex, area.TopLineCount).ToArray()); lines.AddRange(AreaToList(colldata, area.LeftLineIndex, area.LeftLineCount).ToArray()); lines.AddRange(AreaToList(colldata, area.RightLineIndex, area.RightLineCount).ToArray()); lines.AddRange(AreaToList(colldata, area.BottomLineIndex, area.BottomLineCount).ToArray()); g.shapes = lines.ToArray(); groups.Add(g); } svg.groups = groups.ToArray(); using (var settings = new XmlTextWriter(new FileStream(filename, FileMode.Create), Encoding.UTF8)) { settings.Indentation = 4; settings.Formatting = Formatting.Indented; //settings.Namespaces = false; //settings.Settings.OmitXmlDeclaration = true; XmlSerializer serializer = new XmlSerializer(typeof(svg)); serializer.Serialize(settings, svg); } }
private static List <svgShape> AreaToList(SBM_Coll_Data colldata, int start, int count) { var list = new List <svgShape>(); for (int i = start; i < start + count; i++) { var link = colldata.Links[i]; svgLine line = new svgLine() { x1 = 500 + colldata.Vertices[link.VertexIndex1].X, y1 = 500 - colldata.Vertices[link.VertexIndex1].Y, x2 = 500 + colldata.Vertices[link.VertexIndex2].X, y2 = 500 - colldata.Vertices[link.VertexIndex2].Y }; line.style = materialToColor[(CollMaterial)link.Material]; list.Add(line); } return(list); }
/// <summary> /// /// </summary> /// <param name="collData"></param> /// <param name="ssf"></param> public static void ImportCollDataFromSSF(SBM_Coll_Data collData, SSF ssf) { List <CollLine> lines = new List <CollLine>(); List <CollLineGroup> groups = new List <CollLineGroup>(); foreach (var v in ssf.Groups) { var group = new CollLineGroup(); List <CollVertex> vertices = new List <CollVertex>(); foreach (var vert in v.Vertices) { vertices.Add(new CollVertex(vert.X, vert.Y)); } foreach (var l in v.Lines) { var line = new CollLine(); line.v1 = vertices[l.Vertex1]; line.v2 = vertices[l.Vertex2]; var slope = line.Slope; line.Group = group; if (l.Flags.HasFlag(SSFLineFlag.LeftLedge) || l.Flags.HasFlag(SSFLineFlag.RightLedge)) { line.Flag |= CollProperty.LedgeGrab; } if (l.Flags.HasFlag(SSFLineFlag.DropThrough)) { line.Flag |= CollProperty.DropThrough; } line.Material = MaterialTranslate(l.Material); line.GuessCollisionFlag(); lines.Add(line); } group.CalcuateRange(vertices); groups.Add(group); } CollDataBuilder.GenerateCollData(lines, groups, collData); }
/// <summary> /// /// </summary> /// <param name="collData"></param> public static void ExportCollDataToSSF(SBM_Coll_Data collData) { var f = Tools.FileIO.SaveFile("Smash Stage File (SSF)|*.ssf"); if (f == null) { return; } SSF ssf = new SSF(); var LineGroups = new List <CollLineGroup>(); var Lines = new List <CollLine>(); CollDataBuilder.LoadCollData(collData, LineGroups, Lines); var groupIndex = 0; foreach (var g in LineGroups) { SSFGroup group = new SSFGroup(); group.Name = $"Group_{groupIndex++}"; ssf.Groups.Add(group); Dictionary <CollVertex, int> vertexToIndex = new Dictionary <CollVertex, int>(); // bone is unknown to coll_data foreach (var l in Lines) { if (l.Group == g) { var line = new SSFLine(); if (l.Flag.HasFlag(CollProperty.DropThrough)) { line.Flags |= SSFLineFlag.DropThrough; } if (l.Flag.HasFlag(CollProperty.LedgeGrab)) { line.Flags |= SSFLineFlag.LeftLedge; //TODO: proper ledge } line.Material = l.Material.ToString().ToLower(); if (!vertexToIndex.ContainsKey(l.v1)) { vertexToIndex.Add(l.v1, group.Vertices.Count); group.Vertices.Add(new SSFVertex() { X = l.X1, Y = l.Y1 }); } if (!vertexToIndex.ContainsKey(l.v2)) { vertexToIndex.Add(l.v2, group.Vertices.Count); group.Vertices.Add(new SSFVertex() { X = l.X2, Y = l.Y2 }); } line.Vertex1 = vertexToIndex[l.v1]; line.Vertex2 = vertexToIndex[l.v2]; group.Lines.Add(line); } } } // TODO: general points ssf.Save(f); }
/// <summary> /// /// </summary> /// <param name="CollData"></param> /// <param name="LineGroups"></param> /// <param name="Lines"></param> public static void LoadCollData(SBM_Coll_Data CollData, IList <CollLineGroup> LineGroups, IList <CollLine> Lines) { // Load Vertices Dictionary <int, CollVertex> indexToVertex = new Dictionary <int, CollVertex>(); Dictionary <CollVertex, int> vertexToIndex = new Dictionary <CollVertex, int>(); List <Vector2> v = new List <Vector2>(); foreach (var ve in CollData.Vertices) { var vert = new CollVertex(ve.X, ve.Y); indexToVertex.Add(v.Count, vert); vertexToIndex.Add(vert, v.Count); v.Add(new Vector2(ve.X, ve.Y)); } // Frame Viewport //PluginManager.GetCommonViewport().FrameView(v); var links = CollData.Links; var verts = CollData.Vertices; var groups = CollData.LineGroups.ToList(); //List<Line> Lines = new List<Line>(); for (int lineIndex = 0; lineIndex < links.Length; lineIndex++) { var line = links[lineIndex]; Lines.Add(new CollLine() { v1 = indexToVertex[line.VertexIndex1], v2 = indexToVertex[line.VertexIndex2], Material = line.Material, Flag = line.Flag, CollisionFlag = line.CollisionFlag, DynamicCollision = lineIndex >= CollData.DynamicLinksOffset && lineIndex < CollData.DynamicLinksOffset + CollData.DynamicLinksCount }); } for (int lineIndex = 0; lineIndex < links.Length; lineIndex++) { var line = links[lineIndex]; var l = Lines[lineIndex]; if (line.NextLineAltGroup != -1) { l.AltNext = Lines[line.NextLineAltGroup]; } if (line.PreviousLineAltGroup != -1) { l.AltPrevious = Lines[line.PreviousLineAltGroup]; } } foreach (var group in groups) { // Create group and range var lineGroup = new CollLineGroup(); lineGroup.Range = new Vector4(group.XMin, group.YMin, group.XMax, group.YMax); // add vertices var index = 0; foreach (var l in Lines) { // if the vertex belongs to this group if ((vertexToIndex[l.v1] >= group.VertexStart && vertexToIndex[l.v1] < group.VertexStart + group.VertexCount) || (vertexToIndex[l.v2] >= group.VertexStart && vertexToIndex[l.v2] < group.VertexStart + group.VertexCount)) { l.Group = lineGroup; } // if the line is indexed here /*if ((index >= group.TopLineIndex && index < group.TopLineIndex + group.TopLineCount) || * (index >= group.BottomLineIndex && index < group.BottomLineIndex + group.BottomLineCount) || * (index >= group.LeftLineIndex && index < group.LeftLineIndex + group.LeftLineCount) || * (index >= group.RightLineIndex && index < group.RightLineIndex + group.RightLineCount)) * l.Group = lineGroup;*/ index++; } LineGroups.Add(lineGroup); } }
/// <summary> /// Dumps all the collision information in the <see cref="SBM_Coll_Data"/> structure /// </summary> public static void GenerateCollData(IEnumerable <CollLine> Lines, IEnumerable <CollLineGroup> LineGroups, SBM_Coll_Data CollData) { //TODO: Optimize // gather all tops var topCount = Lines.Count(e => e.CollisionFlag == CollPhysics.Top && !e.DynamicCollision); // gather all bottoms var bottomCount = Lines.Count(e => e.CollisionFlag == CollPhysics.Bottom && !e.DynamicCollision); // gather all rights var leftCount = Lines.Count(e => e.CollisionFlag == CollPhysics.Left && !e.DynamicCollision); // gather all lefts var rightCount = Lines.Count(e => e.CollisionFlag == CollPhysics.Right && !e.DynamicCollision); // gather all dynamic collisions var dynamicCount = Lines.Count(e => e.DynamicCollision); int topOffset = 0; int bottomOffset = topCount; int rightOffset = bottomOffset + bottomCount; int leftOffset = rightOffset + rightCount; int dynamicOffset = leftOffset + leftCount; int totalLines = dynamicOffset + dynamicCount; // create each group creating vertices and links as necessary // TODO: SBM_CollLine[] newLines = new SBM_CollLine[totalLines]; List <SBM_CollVertex> vertices = new List <SBM_CollVertex>(); // cache Dictionary <CollLine, SBM_CollLine> lineToCollLine = new Dictionary <CollLine, SBM_CollLine>(); Dictionary <SBM_CollLine, int> collLineToIndex = new Dictionary <SBM_CollLine, int>(); Dictionary <SBM_CollLine, CollLine> lineToAltNext = new Dictionary <SBM_CollLine, CollLine>(); Dictionary <SBM_CollLine, CollLine> lineToAltPrev = new Dictionary <SBM_CollLine, CollLine>(); // groups List <SBM_CollLineGroup> groups = new List <SBM_CollLineGroup>(); int boff = 0, toff = 0, loff = 0, roff = 0, doff = 0; foreach (var g in LineGroups) { var lines = Lines.Where(e => e.Group == g).ToList(); var groupBottom = lines.Count(e => e.CollisionFlag == CollPhysics.Bottom && !e.DynamicCollision); var groupTop = lines.Count(e => e.CollisionFlag == CollPhysics.Top && !e.DynamicCollision); var groupRight = lines.Count(e => e.CollisionFlag == CollPhysics.Right && !e.DynamicCollision); var groupLeft = lines.Count(e => e.CollisionFlag == CollPhysics.Left && !e.DynamicCollision); var groupDynamic = lines.Count(e => e.DynamicCollision); var group = new SBM_CollLineGroup(); group.XMin = g.Range.X; group.YMin = g.Range.Y; group.XMax = g.Range.Z; group.YMax = g.Range.W; groups.Add(group); if (groupTop > 0) { group.TopLineIndex = (short)(topOffset + toff); } group.TopLineCount = (short)groupTop; if (groupBottom > 0) { group.BottomLineIndex = (short)(bottomOffset + boff); } group.BottomLineCount = (short)groupBottom; if (groupRight > 0) { group.RightLineIndex = (short)(rightOffset + roff); } group.RightLineCount = (short)groupRight; if (groupLeft > 0) { group.LeftLineIndex = (short)(leftOffset + loff); } group.LeftLineCount = (short)groupLeft; if (groupDynamic > 0) { group.DynamicLineIndex = (short)(dynamicOffset + doff); } group.DynamicLineCount = (short)groupDynamic; Dictionary <CollLine, CollLine> nextPointToLine = new Dictionary <CollLine, CollLine>(); Dictionary <CollLine, CollLine> prevPointToLine = new Dictionary <CollLine, CollLine>(); List <Vector2> groupVertices = new List <Vector2>(); foreach (var l in lines) { var line = new SBM_CollLine(); line.NextLineAltGroup = -1; line.NextLine = -1; line.PreviousLine = -1; line.PreviousLineAltGroup = -1; var v1 = l.v1.ToVector2(); var v2 = l.v2.ToVector2(); var prevPoint = lines.Find(e => e != l && e.v1 == l.v2); var nextPoint = lines.Find(e => e != l && e.v2 == l.v1); if (prevPoint != null) { prevPointToLine.Add(l, prevPoint); } if (nextPoint != null) { nextPointToLine.Add(l, nextPoint); } if (l.AltNext != null && Lines.Contains(l.AltNext)) { lineToAltNext.Add(line, l.AltNext); } if (l.AltPrevious != null && Lines.Contains(l.AltPrevious)) { lineToAltPrev.Add(line, l.AltPrevious); } // set vertices // TODO: ew, clean this if (!groupVertices.Contains(v1)) { groupVertices.Add(v1); } if (!groupVertices.Contains(v2)) { groupVertices.Add(v2); } line.VertexIndex1 = (short)(vertices.Count + groupVertices.IndexOf(v1)); line.VertexIndex2 = (short)(vertices.Count + groupVertices.IndexOf(v2)); line.Material = l.Material; line.Flag = l.Flag; line.CollisionFlag = l.CollisionFlag; // set the index int lineIndex = -1; if (l.DynamicCollision) { lineIndex = dynamicOffset + doff++; } else { switch (l.CollisionFlag) { case CollPhysics.Bottom: lineIndex = bottomOffset + boff++; break; case CollPhysics.Top: lineIndex = topOffset + toff++; break; case CollPhysics.Left: lineIndex = leftOffset + loff++; break; case CollPhysics.Right: lineIndex = rightOffset + roff++; break; } } collLineToIndex.Add(line, lineIndex); lineToCollLine.Add(l, line); newLines[lineIndex] = line; } // Update Links foreach (var l in lines) { var line = lineToCollLine[l]; if (prevPointToLine.ContainsKey(l)) { line.PreviousLine = (short)collLineToIndex[lineToCollLine[prevPointToLine[l]]]; } if (nextPointToLine.ContainsKey(l)) { line.NextLine = (short)collLineToIndex[lineToCollLine[nextPointToLine[l]]]; } } group.VertexStart = (short)vertices.Count; group.VertexCount = (short)groupVertices.Count; foreach (var v in groupVertices) { vertices.Add(new SBM_CollVertex() { X = v.X, Y = v.Y }); } } // update alt group links foreach (var v in newLines) { if (lineToAltNext.ContainsKey(v)) { v.NextLineAltGroup = (short)collLineToIndex[lineToCollLine[lineToAltNext[v]]]; } if (lineToAltPrev.ContainsKey(v)) { v.PreviousLineAltGroup = (short)collLineToIndex[lineToCollLine[lineToAltPrev[v]]]; } } // dump to file if (topCount != 0) { CollData.TopLinksOffset = (short)topOffset; CollData.TopLinksCount = (short)topCount; } if (bottomCount != 0) { CollData.BottomLinksOffset = (short)bottomOffset; CollData.BottomLinksCount = (short)bottomCount; } if (rightCount != 0) { CollData.RightLinksOffset = (short)rightOffset; CollData.RightLinksCount = (short)rightCount; } if (leftCount != 0) { CollData.LeftLinksOffset = (short)leftOffset; CollData.LeftLinksCount = (short)leftCount; } if (dynamicCount != 0) { CollData.DynamicLinksOffset = (short)dynamicOffset; CollData.DynamicLinksCount = (short)dynamicCount; } CollData.Vertices = vertices.ToArray(); CollData.Links = newLines.ToArray(); CollData.LineGroups = groups.ToArray(); }
/// <summary> /// Opens dat file from stream /// </summary> /// <param name="stream"></param> public void Open(Stream stream) { using (BinaryReaderExt r = new BinaryReaderExt(stream)) { r.BigEndian = true; // Parse Header ----------------------------- var fsize = r.ReadInt32(); // dat size int relocOffset = r.ReadInt32() + 0x20; int relocCount = r.ReadInt32(); int rootCount = r.ReadInt32(); int refCount = r.ReadInt32(); VersionChars = r.ReadChars(4); // Parse Relocation Table ----------------------------- List <int> Offsets = new List <int>(); HashSet <int> OffsetContain = new HashSet <int>(); Dictionary <int, int> relocOffsets = new Dictionary <int, int>(); Offsets.Add(relocOffset); r.BaseStream.Position = relocOffset; for (int i = 0; i < relocCount; i++) { int offset = r.ReadInt32() + 0x20; var temp = r.BaseStream.Position; r.BaseStream.Position = offset; var objectOff = r.ReadInt32() + 0x20; // if we need to read past end of file then we need to include filesize as an offset // this fixes files that had previously been manually relocated to end of file if (objectOff > relocOffset && !Offsets.Contains(fsize)) { Offsets.Add(fsize); } // if (objectOff < 0) { r.BaseStream.Position = temp; continue; } relocOffsets.Add(offset, objectOff); if (!OffsetContain.Contains(objectOff)) { OffsetContain.Add(objectOff); Offsets.Add(objectOff); } r.BaseStream.Position = temp; } // Parse Roots--------------------------------- List <int> rootOffsets = new List <int>(); List <string> rootStrings = new List <string>(); List <int> refOffsets = new List <int>(); List <string> refStrings = new List <string>(); var stringStart = r.BaseStream.Position + (refCount + rootCount) * 8; for (int i = 0; i < rootCount; i++) { rootOffsets.Add(r.ReadInt32() + 0x20); rootStrings.Add(r.ReadString((int)stringStart + r.ReadInt32(), -1)); } for (int i = 0; i < refCount; i++) { var refp = r.ReadInt32() + 0x20; refOffsets.Add(refp); refStrings.Add(r.ReadString((int)stringStart + r.ReadInt32(), -1)); var temp = r.Position; var special = refp; while (true) { r.Seek((uint)special); special = r.ReadInt32(); if (special == 0 || special == -1) { break; } special += 0x20; relocOffsets.Add(refp, special); refp = special; if (!OffsetContain.Contains(special)) { OffsetContain.Add(special); Offsets.Add(special); } } r.Seek(temp); } foreach (var v in rootOffsets) { if (!OffsetContain.Contains(v)) { OffsetContain.Add(v); Offsets.Add(v); } } foreach (var v in refOffsets) { if (!OffsetContain.Contains(v)) { OffsetContain.Add(v); Offsets.Add(v); } } // Split Raw Struct Data-------------------------- Offsets.Sort(); Dictionary <int, HSDStruct> offsetToStruct = new Dictionary <int, HSDStruct>(); Dictionary <int, List <int> > offsetToOffsets = new Dictionary <int, List <int> >(); Dictionary <int, List <int> > offsetToInnerOffsets = new Dictionary <int, List <int> >(); var relockeys = relocOffsets.Keys.ToList(); for (int i = 0; i < Offsets.Count - 1; i++) { r.BaseStream.Position = Offsets[i]; byte[] data = r.ReadBytes(Offsets[i + 1] - Offsets[i]); if (!offsetToOffsets.ContainsKey(Offsets[i])) { var relocKets = relockeys.FindAll(e => e >= Offsets[i] && e < Offsets[i + 1]); var list = new List <int>(); foreach (var k in relocKets) { list.Add(relocOffsets[k]); } offsetToOffsets.Add(Offsets[i], list); offsetToInnerOffsets.Add(Offsets[i], relocKets); } if (!offsetToStruct.ContainsKey(Offsets[i])) { var struture = new HSDStruct(data); offsetToStruct.Add(Offsets[i], struture); } } // set references------------------------- foreach (var str in offsetToStruct) { var offsets = offsetToOffsets[str.Key]; var innerOffsets = offsetToInnerOffsets[str.Key]; for (int i = 0; i < offsets.Count; i++) { if (offsetToStruct.ContainsKey(offsets[i]) && str.Value.Length >= innerOffsets[i] - str.Key + 4) { str.Value.SetReferenceStruct(innerOffsets[i] - str.Key, offsetToStruct[offsets[i]]); } } _structCache.Add(str.Value); _structCacheToOffset.Add(str.Value, str.Key); } // set roots for (int i = 0; i < rootOffsets.Count; i++) { HSDStruct str = offsetToStruct[rootOffsets[i]]; HSDAccessor a = new HSDAccessor(); a._s = str; if (rootStrings[i].EndsWith("shapeanim_joint")) { var acc = new HSDAccessor(); acc._s = str; a = acc; } else if (rootStrings[i].EndsWith("matanim_joint")) { var acc = new HSD_MatAnimJoint(); acc._s = str; a = acc; } else if (rootStrings[i].EndsWith("_joint")) { var jobj = new HSD_JOBJ(); jobj._s = str; a = jobj; } else if (rootStrings[i].EndsWith("_animjoint")) { var jobj = new HSD_AnimJoint(); jobj._s = str; a = jobj; } else if (rootStrings[i].EndsWith("_texanim")) { var jobj = new HSD_TexAnim(); jobj._s = str; a = jobj; } else if (rootStrings[i].EndsWith("_figatree")) { var jobj = new HSD_FigaTree(); jobj._s = str; a = jobj; } else if (rootStrings[i].EndsWith("_scene_models") || rootStrings[i].Equals("Stc_rarwmdls") || rootStrings[i].Equals("Stc_scemdls") || rootStrings[i].Equals("lupe") || rootStrings[i].Equals("tdsce")) { var jobj = new HSDNullPointerArrayAccessor <HSD_JOBJDesc>(); jobj._s = str; a = jobj; } else if (rootStrings[i].StartsWith("ftData")) { var acc = new SBM_PlayerData(); acc._s = str; a = acc; } else if (rootStrings[i].EndsWith("MnSelectChrDataTable")) { var acc = new SBM_SelectChrDataTable(); acc._s = str; a = acc; } else if (rootStrings[i].EndsWith("MnSelectStageDataTable")) { var acc = new SBM_MnSelectStageDataTable(); acc._s = str; a = acc; } else if (rootStrings[i].EndsWith("coll_data")) { var acc = new SBM_Coll_Data(); acc._s = str; a = acc; } else if (rootStrings[i].EndsWith("scene_data") || rootStrings[i].Equals("pnlsce") || rootStrings[i].Equals("flmsce") || (rootStrings[i].StartsWith("Sc") && str.Length == 0x10)) { var acc = new HSD_SOBJ(); acc._s = str; a = acc; } else if (rootStrings[i].StartsWith("map_plit")) { var acc = new HSDNullPointerArrayAccessor <HSD_Light>(); acc._s = str; a = acc; } /*else * if (rootStrings[i].StartsWith("grGroundParam")) * { * var acc = new SBM_GroundParam(); * acc._s = str; * a = acc; * }*/ else if (rootStrings[i].StartsWith("map_head")) { var acc = new SBM_Map_Head(); acc._s = str; a = acc; } else if (rootStrings[i].StartsWith("grGroundParam")) { var acc = new SBM_GroundParam(); acc._s = str; a = acc; } else if (rootStrings[i].StartsWith("vcDataStar")) { var acc = new KAR_vcDataStar(); acc._s = str; a = acc; } else if (rootStrings[i].StartsWith("vcDataWheel")) { var acc = new KAR_vcDataWheel(); acc._s = str; a = acc; } else if (rootStrings[i].StartsWith("grModelMotion")) { var acc = new KAR_grModelMotion(); acc._s = str; a = acc; } else if (rootStrings[i].StartsWith("grModel")) { var acc = new KAR_grModel(); acc._s = str; a = acc; } else if (rootStrings[i].StartsWith("grData")) { var acc = new KAR_grData(); acc._s = str; a = acc; } else if (rootStrings[i].EndsWith("_texg")) { var acc = new HSD_TEXGraphicBank(); acc._s = str; a = acc; } else if (rootStrings[i].EndsWith("_ptcl")) { var acc = new HSD_ParticleGroup(); acc._s = str; a = acc; } else if (rootStrings[i].StartsWith("eff")) { var acc = new SBM_EffectTable(); acc._s = str; a = acc; } Roots.Add(new HSDRootNode() { Name = rootStrings[i], Data = a }); } // set references for (int i = 0; i < refOffsets.Count; i++) { HSDStruct str = offsetToStruct[refOffsets[i]]; HSDAccessor a = new HSDAccessor(); a._s = str; References.Add(new HSDRootNode() { Name = refStrings[i], Data = a }); } } }