diff --git a/StudioSB/GUI/Attachments/LVDAttachment.cs b/StudioSB/GUI/Attachments/LVDAttachment.cs index 69db07a..213ff65 100644 --- a/StudioSB/GUI/Attachments/LVDAttachment.cs +++ b/StudioSB/GUI/Attachments/LVDAttachment.cs @@ -47,7 +47,7 @@ private bool IsActive private LevelData LVD; // Options - private float PlatformWidth = 8f; + private float CollisionDepth = 8.0f; private static float PickRange = 2.5f; public LVDAttachment() @@ -70,7 +70,7 @@ public LVDAttachment() ExportLVD.Click += (sender, args) => { string fileName; - if(FileTools.TrySaveFile(out fileName, "Smash Level Data |*.lvd;*.ssf")) + if (FileTools.TrySaveFile(out fileName, "Smash Level Data |*.lvd;*.ssf")) { if (fileName.EndsWith(".ssf")) { @@ -86,8 +86,8 @@ public LVDAttachment() ToolStripButton addVertex = new ToolStripButton(); addVertex.Text = "Add"; addVertex.Click += (object sender, EventArgs args) => { - if(PropertyGrid.SelectedObject is LVDVector2 point) - AddNewPoint(point); + if (PropertyGrid.SelectedObject is LVDVector2 point) + AddVertex(point); }; ToolStripButton deleteVertex = new ToolStripButton(); deleteVertex.Text = "Delete"; @@ -116,45 +116,181 @@ public LVDAttachment() } /// - /// Reads LVD data + /// Reads LVD file data from the given file name. /// /// public void Open(string FileName) { - LevelData lvd = new LevelData(); - lvd.Open(FileName); + LevelData lvd = new LevelData(FileName); LVD = lvd; RefreshNodes(); } /// - /// refreshes lvd nodes list + /// Refreshes the LVD object node list. /// private void RefreshNodes() { - var lvdNode = new TreeNode() { Text = "LVD", Tag = LVD }; + var levelDataNode = new TreeNode() { Text = "LVD", Tag = LVD }; + NodeTree.Nodes.Clear(); - NodeTree.Nodes.Add(lvdNode); + NodeTree.Nodes.Add(levelDataNode); + + var collisionNodes = new TreeNode() { Text = "Collisions" }; + var startPositionNodes = new TreeNode() { Text = "Start Positions" }; + var restartPositionNodes = new TreeNode() { Text = "Restart Positions" }; + var cameraRegionNodes = new TreeNode() { Text = "Camera Regions" }; + var deathRegionNodes = new TreeNode() { Text = "Death Regions" }; + var enemyGeneratorNodes = new TreeNode() { Text = "Enemy Generators" }; + var damageShapeNodes = new TreeNode() { Text = "Damage Shapes" }; + var itemPopupRegionNodes = new TreeNode() { Text = "Item Popup Regions" }; + var ptrainerRangeNodes = new TreeNode() { Text = "Pokémon Trainer Ranges" }; + var ptrainerFloatingFloorNodes = new TreeNode() { Text = "Pokémon Trainer Platforms" }; + var generalShape2DNodes = new TreeNode() { Text = "General Shapes (2D)" }; + var generalShape3DNodes = new TreeNode() { Text = "General Shapes (3D)" }; + var shrinkedCameraRegionNodes = new TreeNode() { Text = "Shrinked Camera Regions" }; + var shrinkedDeathRegionNodes = new TreeNode() { Text = "Shrinked Death Regions" }; + + levelDataNode.Nodes.Add(collisionNodes); + levelDataNode.Nodes.Add(startPositionNodes); + levelDataNode.Nodes.Add(restartPositionNodes); + levelDataNode.Nodes.Add(cameraRegionNodes); + levelDataNode.Nodes.Add(deathRegionNodes); + levelDataNode.Nodes.Add(enemyGeneratorNodes); + levelDataNode.Nodes.Add(damageShapeNodes); + levelDataNode.Nodes.Add(itemPopupRegionNodes); + levelDataNode.Nodes.Add(ptrainerRangeNodes); + levelDataNode.Nodes.Add(ptrainerFloatingFloorNodes); + levelDataNode.Nodes.Add(generalShape2DNodes); + levelDataNode.Nodes.Add(generalShape3DNodes); + levelDataNode.Nodes.Add(shrinkedCameraRegionNodes); + levelDataNode.Nodes.Add(shrinkedDeathRegionNodes); + + foreach (var collision in LVD.Collisions) + { + var collisionNode = new TreeNode(); + + collisionNode.Text = collision.MetaInfo.Name; + collisionNode.Tag = collision; + collisionNodes.Nodes.Add(collisionNode); + } + + foreach (var startPosition in LVD.StartPositions) + { + var startPositionNode = new TreeNode(); + + startPositionNode.Text = startPosition.MetaInfo.Name; + startPositionNode.Tag = startPosition; + startPositionNodes.Nodes.Add(startPositionNode); + } + + foreach (var restartPosition in LVD.RestartPositions) + { + var restartPositionNode = new TreeNode(); + + restartPositionNode.Text = restartPosition.MetaInfo.Name; + restartPositionNode.Tag = restartPosition; + restartPositionNodes.Nodes.Add(restartPositionNode); + } + + foreach (var cameraRegion in LVD.CameraRegions) + { + var cameraRegionNode = new TreeNode(); + + cameraRegionNode.Text = cameraRegion.MetaInfo.Name; + cameraRegionNode.Tag = cameraRegion; + cameraRegionNodes.Nodes.Add(cameraRegionNode); + } + + foreach (var deathRegion in LVD.DeathRegions) + { + var deathRegionNode = new TreeNode(); + + deathRegionNode.Text = deathRegion.MetaInfo.Name; + deathRegionNode.Tag = deathRegion; + deathRegionNodes.Nodes.Add(deathRegionNode); + } + + foreach (var enemyGenerator in LVD.EnemyGenerators) + { + var enemyGeneratorNode = new TreeNode(); + + enemyGeneratorNode.Text = enemyGenerator.MetaInfo.Name; + enemyGeneratorNode.Tag = enemyGenerator; + enemyGeneratorNodes.Nodes.Add(enemyGeneratorNode); + } + + foreach (var damageShape in LVD.DamageShapes) + { + var damageShapeNode = new TreeNode(); + + damageShapeNode.Text = damageShape.MetaInfo.Name; + damageShapeNode.Tag = damageShape; + damageShapeNodes.Nodes.Add(damageShapeNode); + } + + foreach (var itemPopupRegion in LVD.ItemPopupRegions) + { + var itemPopupRegionNode = new TreeNode(); + + itemPopupRegionNode.Text = itemPopupRegion.MetaInfo.Name; + itemPopupRegionNode.Tag = itemPopupRegion; + itemPopupRegionNodes.Nodes.Add(itemPopupRegionNode); + } + + foreach (var ptrainerRange in LVD.PTrainerRanges) + { + var ptrainerRangeNode = new TreeNode(); + + ptrainerRangeNode.Text = ptrainerRange.MetaInfo.Name; + ptrainerRangeNode.Tag = ptrainerRange; + ptrainerRangeNodes.Nodes.Add(ptrainerRangeNode); + } + + foreach (var ptrainerFloatingFloor in LVD.PTrainerFloatingFloors) + { + var ptrainerFloatingFloorNode = new TreeNode(); + + ptrainerFloatingFloorNode.Text = ptrainerFloatingFloor.MetaInfo.Name; + ptrainerFloatingFloorNode.Tag = ptrainerFloatingFloor; + ptrainerFloatingFloorNodes.Nodes.Add(ptrainerFloatingFloorNode); + } + + foreach (var generalShape2D in LVD.GeneralShapes2D) + { + var generalShape2DNode = new TreeNode(); - var collisionNode = new TreeNode() { Text = "Collisions" }; - var itemSpawnerNode = new TreeNode() { Text = "ItemSpawners" }; - lvdNode.Nodes.Add(collisionNode); - lvdNode.Nodes.Add(itemSpawnerNode); + generalShape2DNode.Text = generalShape2D.MetaInfo.Name; + generalShape2DNode.Tag = generalShape2D; + generalShape2DNodes.Nodes.Add(generalShape2DNode); + } - foreach (var col in LVD.Collisions) + foreach (var generalShape3D in LVD.GeneralShapes3D) { - var colNode = new TreeNode(); - colNode.Text = col.EntryLabel; - colNode.Tag = col; - collisionNode.Nodes.Add(colNode); + var generalShape3DNode = new TreeNode(); + + generalShape3DNode.Text = generalShape3D.MetaInfo.Name; + generalShape3DNode.Tag = generalShape3D; + generalShape3DNodes.Nodes.Add(generalShape3DNode); + } + + foreach (var shrinkedCameraRegion in LVD.ShrinkedCameraRegions) + { + var shrinkedCameraRegionNode = new TreeNode(); + + shrinkedCameraRegionNode.Text = shrinkedCameraRegion.MetaInfo.Name; + shrinkedCameraRegionNode.Tag = shrinkedCameraRegion; + shrinkedCameraRegionNodes.Nodes.Add(shrinkedCameraRegionNode); } - foreach (var item in LVD.ItemSpawners) + + foreach (var shrinkedDeathRegion in LVD.ShrinkedDeathRegions) { - var itemNode = new TreeNode(); - itemNode.Text = item.EntryLabel; - itemNode.Tag = item; - itemSpawnerNode.Nodes.Add(itemNode); + var shrinkedDeathRegionNode = new TreeNode(); + + shrinkedDeathRegionNode.Text = shrinkedDeathRegion.MetaInfo.Name; + shrinkedDeathRegionNode.Tag = shrinkedDeathRegion; + shrinkedDeathRegionNodes.Nodes.Add(shrinkedDeathRegionNode); } } @@ -167,6 +303,7 @@ private void SelectObjectChanged(object sender, EventArgs args) { ToolPanel.Controls.Clear(); ToolPanel.Text = "LVD Options"; + if (PropertyGrid.SelectedObject is LVDVector2) { ToolPanel.Text = "Point Options"; @@ -185,9 +322,9 @@ private void SelectObjectChanged(object sender, EventArgs args) /// private void SelectNode(object sender, EventArgs args) { - if(NodeTree.SelectedNode != null) + if (NodeTree.SelectedNode != null) { - if(NodeTree.SelectedNode.Tag != null) + if (NodeTree.SelectedNode.Tag != null) { PropertyGrid.SelectedObject = NodeTree.SelectedNode.Tag; } @@ -219,105 +356,118 @@ public void OnAttach(SBViewportPanel viewportPanel) public void Pick(Ray ray) { if (!IsActive) + { return; + } PropertyGrid.SelectedObject = null; - var depthPicked = ray.GetPlaneIntersection(-Vector3.UnitZ, new Vector3(0, 0, -PlatformWidth / 2)); + var depthPicked = ray.GetPlaneIntersection(-Vector3.UnitZ, new Vector3(0.0f, 0.0f, -CollisionDepth / 2.0f)); Picked = ray.GetPlaneIntersection(-Vector3.UnitZ, Vector3.Zero); Vector2 nearestLine; float closest = float.MaxValue; - LVDCollisionMaterial collisionMat = null; - - foreach(var point in LVD.GeneralPoints) + LVDCollisionAttribute collisionAttribute = null; + + foreach (var collision in LVD.Collisions) { - if (CrossMath.FastDistance(Picked, new Vector3(point.X, point.Y, point.Z), PickRange * 2.5f)) + Vector2 startPos = (collision.IsDynamic && collision.Dynamic) ? new Vector2(collision.DynamicOffset.X, collision.DynamicOffset.Y) : new Vector2(0.0f, 0.0f); + + for (int i = 0; i < collision.Vertices.Count; i++) { - PropertyGrid.SelectedObject = point; - return; + var v1 = collision.Vertices[i]; + + if (i < collision.Attributes.Count) + { + var v2 = collision.Vertices[i + 1]; + var distance = Ray.GetDistanceToSegment(depthPicked.Xy, new Vector2(v1.X + startPos.X, v1.Y + startPos.Y), new Vector2(v2.X + startPos.X, v2.Y + startPos.Y), out nearestLine); + + if (distance < CollisionDepth / 4.0f & distance < closest) + { + closest = distance; + collisionAttribute = collision.Attributes[i]; + } + } + + if (CrossMath.FastDistance(Picked, new Vector3(v1.X + startPos.X, v1.Y + startPos.Y, 0.0f), PickRange)) + { + PropertyGrid.SelectedObject = v1; + return; + } } } - foreach (var bound in LVD.CameraBounds) + + foreach (var startPosition in LVD.StartPositions) { - if (Ray.CheckBoundHit(Picked.Xy, new Vector2(bound.Left, bound.Top), new Vector2(bound.Right, bound.Bottom), PickRange)) + if (CrossMath.FastDistance(Picked, new Vector3(startPosition.Position.X, startPosition.Position.Y, 0.0f), PickRange * 2.5f)) { - PropertyGrid.SelectedObject = bound; + PropertyGrid.SelectedObject = startPosition; return; } } - foreach (var bound in LVD.BlastZoneBounds) + + foreach (var restartPosition in LVD.RestartPositions) { - if(Ray.CheckBoundHit(Picked.Xy, new Vector2(bound.Left, bound.Top), new Vector2(bound.Right, bound.Bottom), PickRange)) + if (CrossMath.FastDistance(Picked, new Vector3(restartPosition.Position.X, restartPosition.Position.Y, 0.0f), PickRange * 2.5f)) { - PropertyGrid.SelectedObject = bound; + PropertyGrid.SelectedObject = restartPosition; return; } } - foreach (var bound in LVD.ShrunkBlastZoneBounds) + + foreach (var cameraRegion in LVD.CameraRegions) { - if (Ray.CheckBoundHit(Picked.Xy, new Vector2(bound.Left, bound.Top), new Vector2(bound.Right, bound.Bottom), PickRange)) + if (Ray.CheckBoundHit(Picked.Xy, new Vector2(cameraRegion.Rectangle.Left, cameraRegion.Rectangle.Top), new Vector2(cameraRegion.Rectangle.Right, cameraRegion.Rectangle.Bottom), PickRange)) { - PropertyGrid.SelectedObject = bound; + PropertyGrid.SelectedObject = cameraRegion; return; } } - foreach (var bound in LVD.ShrunkCameraBounds) + + foreach (var deathRegion in LVD.DeathRegions) { - if (Ray.CheckBoundHit(Picked.Xy, new Vector2(bound.Left, bound.Top), new Vector2(bound.Right, bound.Bottom), PickRange)) + if (Ray.CheckBoundHit(Picked.Xy, new Vector2(deathRegion.Rectangle.Left, deathRegion.Rectangle.Top), new Vector2(deathRegion.Rectangle.Right, deathRegion.Rectangle.Bottom), PickRange)) { - PropertyGrid.SelectedObject = bound; + PropertyGrid.SelectedObject = deathRegion; return; } } - foreach (var spawn in LVD.Spawns) + + foreach (var generalShape3D in LVD.GeneralShapes3D) { - if(CrossMath.FastDistance(Picked, new Vector3(spawn.X, spawn.Y, 0), PickRange * 2.5f)) + if (generalShape3D.Shape.Type == LVDShape3Type.Point && CrossMath.FastDistance(Picked, new Vector3(generalShape3D.Shape.X, generalShape3D.Shape.Y, generalShape3D.Shape.Z), PickRange * 2.5f)) { - PropertyGrid.SelectedObject = spawn; + PropertyGrid.SelectedObject = generalShape3D; return; } } - foreach (var spawn in LVD.Respawns) + + foreach (var shrinkedCameraRegion in LVD.ShrinkedCameraRegions) { - if (CrossMath.FastDistance(Picked, new Vector3(spawn.X, spawn.Y, 0), PickRange * 2.5f)) + if (Ray.CheckBoundHit(Picked.Xy, new Vector2(shrinkedCameraRegion.Rectangle.Left, shrinkedCameraRegion.Rectangle.Top), new Vector2(shrinkedCameraRegion.Rectangle.Right, shrinkedCameraRegion.Rectangle.Bottom), PickRange)) { - PropertyGrid.SelectedObject = spawn; + PropertyGrid.SelectedObject = shrinkedCameraRegion; return; } } - foreach (var col in LVD.Collisions) + + foreach (var shrinkedDeathRegion in LVD.ShrinkedDeathRegions) { - for(int i =0; i < col.Vertices.Count; i++) + if (Ray.CheckBoundHit(Picked.Xy, new Vector2(shrinkedDeathRegion.Rectangle.Left, shrinkedDeathRegion.Rectangle.Top), new Vector2(shrinkedDeathRegion.Rectangle.Right, shrinkedDeathRegion.Rectangle.Bottom), PickRange)) { - var vert = col.Vertices[i]; - if (i < col.Materials.Count) - { - var vert2 = col.Vertices[i+1]; - var dis = Ray.GetDistanceToSegment(depthPicked.Xy, new Vector2(vert.X, vert.Y), new Vector2(vert2.X, vert2.Y), out nearestLine); - if (dis < PlatformWidth / 4 & dis < closest) - { - closest = dis; - collisionMat = col.Materials[i]; - } - } - if (CrossMath.FastDistance(Picked, new Vector3(vert.X, vert.Y, 0), PickRange)) - { - PropertyGrid.SelectedObject = vert; - return; - } + PropertyGrid.SelectedObject = shrinkedDeathRegion; + return; } } - if (PropertyGrid.SelectedObject == null && collisionMat != null) - PropertyGrid.SelectedObject = collisionMat; + if (PropertyGrid.SelectedObject == null && collisionAttribute != null) + PropertyGrid.SelectedObject = collisionAttribute; } public void OnRemove(SBViewportPanel viewportPanel) { } - bool DeleteDown = false; bool ADown = false; @@ -326,8 +476,12 @@ public void Step(SBViewport viewport) var mouseP = viewport.GetMousePosition(); var deltaMouse = PrevMousePosition - mouseP; PrevMousePosition = mouseP; + if (!IsActive) + { return; + } + if (Keyboard.GetState().IsKeyDown(Key.AltLeft)) { if (Keyboard.GetState().IsKeyDown(Key.A)) @@ -337,52 +491,70 @@ public void Step(SBViewport viewport) ADown = true; if (PropertyGrid.SelectedObject is LVDVector2 v) - AddNewPoint(v); + { + AddVertex(v); + } } } else + { ADown = false; + } + if (Mouse.GetState().IsButtonDown(MouseButton.Left)) { - if (PropertyGrid.SelectedObject is LVDGeneralPoint point) + if (PropertyGrid.SelectedObject is LVDPoint point) { - point.StartPosition.X -= deltaMouse.X / 4; - point.StartPosition.Y += deltaMouse.Y / 4; - point.X -= deltaMouse.X / 4; - point.Y += deltaMouse.Y / 4; + point.DynamicOffset.X -= deltaMouse.X / 4.0f; + point.DynamicOffset.Y += deltaMouse.Y / 4.0f; + point.Position.X -= deltaMouse.X / 4.0f; + point.Position.Y += deltaMouse.Y / 4.0f; PropertyGrid.SelectedObject = PropertyGrid.SelectedObject; } - if (PropertyGrid.SelectedObject is LVDSpawn spawn) + + if (PropertyGrid.SelectedObject is LVDGeneralShape3 generalShape3D) { - spawn.StartPosition.X -= deltaMouse.X / 4; - spawn.StartPosition.Y += deltaMouse.Y / 4; - spawn.X -= deltaMouse.X / 4; - spawn.Y += deltaMouse.Y / 4; + generalShape3D.DynamicOffset.X -= deltaMouse.X / 4.0f; + generalShape3D.DynamicOffset.Y += deltaMouse.Y / 4.0f; + generalShape3D.Shape.X -= deltaMouse.X / 4.0f; + generalShape3D.Shape.Y += deltaMouse.Y / 4.0f; PropertyGrid.SelectedObject = PropertyGrid.SelectedObject; } + if (PropertyGrid.SelectedObject is LVDVector2 v) { - v.X -= deltaMouse.X / 4; - v.Y += deltaMouse.Y / 4; + v.X -= deltaMouse.X / 4.0f; + v.Y += deltaMouse.Y / 4.0f; - // recalculate normals - // is there a better way to do this? - foreach (var col in LVD.Collisions) + // Recalculate all collision unit normal vectors. + // TODO: Is there a better way to do this? + foreach (var collision in LVD.Collisions) { - int index = col.Vertices.IndexOf(v); - if (index == -1) continue; + int index = collision.Vertices.IndexOf(v); + + if (index == -1) + { + continue; + } + + if (index < collision.Normals.Count) + { + collision.Normals[index] = LVDVector2.GenerateNormal(v, collision.Vertices[index + 1]); + } - if (index < col.Normals.Count) - col.Normals[index] = LVDVector2.GenerateNormal(v, col.Vertices[index + 1]); if (index > 0) - col.Normals[index - 1] = LVDVector2.GenerateNormal(col.Vertices[index - 1], v); + { + collision.Normals[index - 1] = LVDVector2.GenerateNormal(collision.Vertices[index - 1], v); + } + break; } + PropertyGrid.SelectedObject = PropertyGrid.SelectedObject; } - } } + if (Keyboard.GetState().IsKeyDown(Key.Delete)) { if (!DeleteDown) @@ -390,12 +562,15 @@ public void Step(SBViewport viewport) DeleteDown = true; if (PropertyGrid.SelectedObject is LVDVector2 v) + { DeleteVertex(v); + } } } else + { DeleteDown = false; - + } } private Vector2 PrevMousePosition; @@ -408,32 +583,36 @@ public void Update(SBViewport viewport) /// adds new point after vector /// /// - private void AddNewPoint(LVDVector2 v) + private void AddVertex(LVDVector2 v) { - foreach (var col in LVD.Collisions) + foreach (var collision in LVD.Collisions) { - int index = col.Vertices.IndexOf(v); - if (index == -1) continue; + int index = collision.Vertices.IndexOf(v); - if (index == col.Vertices.Count - 1) + if (index == -1) { - var newPoint = new LVDVector2(v.X + 3, v.Y); - var newMaterial = new LVDCollisionMaterial(); - newMaterial.Physics = col.Materials[index - 1].Physics; - col.Vertices.Add(newPoint); - col.Normals.Add(LVDVector2.GenerateNormal(v, newPoint)); - col.Materials.Add(newMaterial); + continue; + } + + if (index == collision.Vertices.Count - 1) + { + var newPoint = new LVDVector2(v.X + 3.0f, v.Y); + var newAttribute = new LVDCollisionAttribute(); + newAttribute.Type = collision.Attributes[index - 1].Type; + collision.Vertices.Add(newPoint); + collision.Normals.Add(LVDVector2.GenerateNormal(v, newPoint)); + collision.Attributes.Add(newAttribute); PropertyGrid.SelectedObject = newPoint; } else { - var newPoint = new LVDVector2((v.X + col.Vertices[index + 1].X) / 2, (v.Y + col.Vertices[index + 1].Y) / 2); - var newMaterial = new LVDCollisionMaterial(); - newMaterial.Physics = col.Materials[index].Physics; - var newNormal = LVDVector2.GenerateNormal(newPoint, col.Vertices[index + 1]); - col.Normals.Insert(index + 1, newNormal); - col.Materials.Insert(index + 1, newMaterial); - col.Vertices.Insert(index + 1, newPoint); + var newPoint = new LVDVector2((v.X + collision.Vertices[index + 1].X) / 2.0f, (v.Y + collision.Vertices[index + 1].Y) / 2.0f); + var newAttribute = new LVDCollisionAttribute(); + newAttribute.Type = collision.Attributes[index].Type; + var newNormal = LVDVector2.GenerateNormal(newPoint, collision.Vertices[index + 1]); + collision.Normals.Insert(index + 1, newNormal); + collision.Attributes.Insert(index + 1, newAttribute); + collision.Vertices.Insert(index + 1, newPoint); PropertyGrid.SelectedObject = newPoint; } @@ -442,54 +621,63 @@ private void AddNewPoint(LVDVector2 v) } /// - /// deletes lvdvector2 + /// Deletes a vertex. /// /// private void DeleteVertex(LVDVector2 v) { LVDCollision remove = null; - foreach (var col in LVD.Collisions) + + foreach (var collision in LVD.Collisions) { - int index = col.Vertices.IndexOf(v); - if (index == -1) continue; + int index = collision.Vertices.IndexOf(v); + + if (index == -1) + { + continue; + } if (index >= 1) - PropertyGrid.SelectedObject = col.Vertices[index - 1]; + { + PropertyGrid.SelectedObject = collision.Vertices[index - 1]; + } - if(col.Normals.Count > 0) + if (collision.Normals.Count > 0) { - if (index == col.Normals.Count) + if (index == collision.Normals.Count) { - col.Normals.RemoveAt(index - 1); - col.Materials.RemoveAt(index - 1); + collision.Normals.RemoveAt(index - 1); + collision.Attributes.RemoveAt(index - 1); } else { - col.Normals.RemoveAt(index); - col.Materials.RemoveAt(index); + collision.Normals.RemoveAt(index); + collision.Attributes.RemoveAt(index); } } - col.Vertices.RemoveAt(index); + collision.Vertices.RemoveAt(index); - if (index == col.Vertices.Count) + if (index == collision.Vertices.Count) + { index--; + } - if (col.Normals.Count > 0 && index > 0) + if (collision.Normals.Count > 0 && index > 0) { - col.Normals[index - 1] = LVDVector2.GenerateNormal(col.Vertices[index - 1], col.Vertices[index]); + collision.Normals[index - 1] = LVDVector2.GenerateNormal(collision.Vertices[index - 1], collision.Vertices[index]); } - if (col.Vertices.Count < 2) + if (collision.Vertices.Count < 2) { - remove = col; + remove = collision; } break; } - // remove collision that is marked for removal - if(remove != null) + // Remove collision that is marked for removal + if (remove != null) { LVD.Collisions.Remove(remove); RefreshNodes(); @@ -498,34 +686,37 @@ private void DeleteVertex(LVDVector2 v) public void Save(string FilePath) { - } #region Rendering private int FlashTimer = 0; private int FlashInterval = 15; - private static Vector3 FlashColor1 = new Vector3(1f, 1f, 1f); - private static Vector3 FlashColor2 = new Vector3(1f, 1f, 0f); + private static Vector3 FlashColor1 = new Vector3(1.0f, 1.0f, 1.0f); + private static Vector3 FlashColor2 = new Vector3(1.0f, 1.0f, 0.0f); private Vector3 FlashColor = FlashColor1; - public void Render(SBViewport viewport, float frame = 0) + public void Render(SBViewport viewport, float frame = 0.0f) { //if (!IsActive) // return; FlashTimer++; + if (FlashTimer > FlashInterval) { FlashTimer = 0; + if (FlashColor == FlashColor1) { FlashColor = FlashColor2; } else + { FlashColor = FlashColor1; + } } - // TODO: draw with shader + // TODO: Draw with shader if (LVD != null) { GL.PushAttrib(AttribMask.AllAttribBits); @@ -535,317 +726,421 @@ public void Render(SBViewport viewport, float frame = 0) GL.UseProgram(0); - GL.Color3(1f, 1f, 0); - GL.LineWidth(2f); + GL.Color3(1.0f, 1.0f, 0.0f); + GL.LineWidth(2.0f); - GL.PointSize(5f); + GL.PointSize(5.0f); GL.Begin(PrimitiveType.Points); GL.Vertex3(Picked.X, Picked.Y, Picked.Z); GL.End(); RenderCollisions(); - foreach(var blast in LVD.BlastZoneBounds) - RenderBounds(blast, Color.LightPink); + int playerIndex = 1; - foreach (var camera in LVD.CameraBounds) - RenderBounds(camera, Color.SkyBlue); + foreach (var startPosition in LVD.StartPositions) + { + if (PropertyGrid.SelectedObject == startPosition) + { + Rendering.TextRenderer.Draw(viewport.Camera, "P" + playerIndex++, Matrix4.CreateTranslation(new Vector3(startPosition.Position.X, startPosition.Position.Y, 0.0f)), FlashColor); + } + else + { + Rendering.TextRenderer.Draw(viewport.Camera, "P" + playerIndex++, Matrix4.CreateTranslation(new Vector3(startPosition.Position.X, startPosition.Position.Y, 0.0f))); + } + } - foreach (var blast in LVD.ShrunkBlastZoneBounds) - RenderBounds(blast, Color.LightPink); + foreach (var restartPosition in LVD.RestartPositions) + { + if (PropertyGrid.SelectedObject == restartPosition) + { + Rendering.Shapes.Spawn.RenderSpawn(restartPosition.Position.X, restartPosition.Position.Y, 5.0f, FlashColor); + } + else + { + Rendering.Shapes.Spawn.RenderSpawn(restartPosition.Position.X, restartPosition.Position.Y, 5.0f, new Vector3(0.95f, 0.95f, 0.95f)); + } + } - foreach (var camera in LVD.ShrunkCameraBounds) - RenderBounds(camera, Color.SkyBlue); + foreach (var cameraRegion in LVD.CameraRegions) + { + RenderRegion(cameraRegion, Color.SkyBlue); + } - int playerIndex = 1; - foreach (var spawn in LVD.Spawns) + foreach (var deathRegion in LVD.DeathRegions) { - if (PropertyGrid.SelectedObject == spawn) - Rendering.TextRenderer.Draw(viewport.Camera, "P" + playerIndex++, Matrix4.CreateTranslation(new Vector3(spawn.X, spawn.Y, 0)), FlashColor); - else - Rendering.TextRenderer.Draw(viewport.Camera, "P" + playerIndex++, Matrix4.CreateTranslation(new Vector3(spawn.X, spawn.Y, 0))); - + RenderRegion(deathRegion, Color.LightPink); } - foreach (var spawn in LVD.Respawns) + foreach (var itemPopupRegion in LVD.ItemPopupRegions) { - if(PropertyGrid.SelectedObject == spawn) - Rendering.Shapes.Spawn.RenderSpawn(spawn.X, spawn.Y, 5, FlashColor); - else - Rendering.Shapes.Spawn.RenderSpawn(spawn.X, spawn.Y, 5, new Vector3(0.95f, 0.95f, 0.95f)); + foreach (var region in itemPopupRegion.Regions) + { + RenderShape(region); + } } - - foreach (var point in LVD.GeneralPoints) + + foreach (var generalShape3D in LVD.GeneralShapes3D) { - Rendering.Shapes.VectorGraphicType graphic = Rendering.Shapes.VectorGraphicType.StarStorm; - Vector3 col = new Vector3(0.75f, 0.85f, 1); - if (point.EntryLabel.Contains("Ike")) + Rendering.Shapes.VectorGraphicType graphic; + Vector3 color; + + if (generalShape3D.DynamicName.Contains("KirifudaPit")) { graphic = Rendering.Shapes.VectorGraphicType.FireEmblem; - col = new Vector3(1, 0.85f, 0.75f); + color = new Vector3(1.0f, 0.85f, 0.75f); } - if (point.EntryLabel.Contains("Pikmin")) + else if (generalShape3D.DynamicName.Contains("KirifudaPikmin")) { graphic = Rendering.Shapes.VectorGraphicType.Pikmin; - col = new Vector3(0.65f, 1, 0.65f); + color = new Vector3(0.65f, 1.0f, 0.65f); + } + else if (generalShape3D.DynamicName.Contains("KirifudaIke")) + { + graphic = Rendering.Shapes.VectorGraphicType.FireEmblem; + color = new Vector3(1.0f, 0.85f, 0.75f); + } + else + { + graphic = Rendering.Shapes.VectorGraphicType.StarStorm; + color = new Vector3(0.75f, 0.85f, 1.0f); } - if (PropertyGrid.SelectedObject == point) - col = FlashColor; - Rendering.Shapes.VectorGraphic.RenderGraphic(graphic, Matrix4.CreateTranslation(point.X, point.Y, point.Z), col, 8); - } - foreach(var spawner in LVD.ItemSpawners) - { - foreach(var shape in spawner.Sections) + if (generalShape3D == PropertyGrid.SelectedObject) { - RenderShape(shape); + color = FlashColor; } + + Rendering.Shapes.VectorGraphic.RenderGraphic(graphic, Matrix4.CreateTranslation(generalShape3D.Shape.X, generalShape3D.Shape.Y, generalShape3D.Shape.Z), color, 8.0f); + } + + foreach (var shrinkedCameraRegion in LVD.ShrinkedCameraRegions) + { + RenderRegion(shrinkedCameraRegion, Color.SkyBlue); + } + + foreach (var shrinkedDeathRegion in LVD.ShrinkedDeathRegions) + { + RenderRegion(shrinkedDeathRegion, Color.LightPink); } GL.PopAttrib(); } - if(PropertyGrid.SelectedObject is LVDVector2) + if (PropertyGrid.SelectedObject is LVDVector2) { - Rendering.TextRenderer.DrawOrtho(viewport.Camera, "Alt+Mouse: Move Point", new Vector2(4, viewport.Camera.RenderHeight - 30)); - Rendering.TextRenderer.DrawOrtho(viewport.Camera, "Alt + A : Add Point", new Vector2(4, viewport.Camera.RenderHeight - 16)); - Rendering.TextRenderer.DrawOrtho(viewport.Camera, "Delete : Delete", new Vector2(4, viewport.Camera.RenderHeight - 2)); + Rendering.TextRenderer.DrawOrtho(viewport.Camera, "Alt+Mouse: Move Point", new Vector2(4.0f, (float)(viewport.Camera.RenderHeight - 30))); + Rendering.TextRenderer.DrawOrtho(viewport.Camera, "Alt + A : Add Point", new Vector2(4.0f, (float)(viewport.Camera.RenderHeight - 16))); + Rendering.TextRenderer.DrawOrtho(viewport.Camera, "Delete : Delete", new Vector2(4.0f, (float)(viewport.Camera.RenderHeight - 2))); } else { - Rendering.TextRenderer.DrawOrtho(viewport.Camera, "Double Click to Select", new Vector2(4, viewport.Camera.RenderHeight - 16)); + Rendering.TextRenderer.DrawOrtho(viewport.Camera, "Double Click to Select", new Vector2(4.0f, (float)(viewport.Camera.RenderHeight - 16))); } } /// - /// Renders collisions from LVD + /// Renders all collisions to the viewport using legacy OpenGL. /// private void RenderCollisions() { - foreach (var col in LVD.Collisions) + foreach (var collision in LVD.Collisions) { - for (int i = 0; i < col.Materials.Count; i++) + for (int i = 0; i < collision.Normals.Count; i++) { - if(PropertyGrid.SelectedObject == col.Vertices[i]) + if (PropertyGrid.SelectedObject == collision.Vertices[i] || PropertyGrid.SelectedObject == collision.Vertices[i + 1]) { - GL.Color3(1f, 1f, 0); - GL.PointSize(12f); + Vector3 startPos = (collision.IsDynamic && collision.Dynamic) ? new Vector3(collision.DynamicOffset.X, collision.DynamicOffset.Y, collision.DynamicOffset.Z) : new Vector3(0.0f, 0.0f, 0.0f); + + GL.Color3(1.0f, 1.0f, 0.0f); + GL.PointSize(12.0f); GL.Begin(PrimitiveType.Points); - GL.Vertex3(col.Vertices[i].X, col.Vertices[i].Y, 0); + GL.Vertex3( + (PropertyGrid.SelectedObject == collision.Vertices[i] ? collision.Vertices[i].X : collision.Vertices[i + 1].X) + startPos.X, + (PropertyGrid.SelectedObject == collision.Vertices[i] ? collision.Vertices[i].Y : collision.Vertices[i + 1].Y) + startPos.Y, + startPos.Z + ); GL.End(); } - RenderWall(col, col.Vertices[i], col.Vertices[i+1], col.Materials[i], new Vector2(col.Normals[i].X, col.Normals[i].Y)); + + RenderEdge( + collision, + collision.Vertices[i], + collision.Vertices[i + 1], + collision.Attributes.Count != 0 ? collision.Attributes[i] : new LVDCollisionAttribute(), + new Vector2(collision.Normals[i].X, collision.Normals[i].Y) + ); } } } /// - /// Renders a collision wall + /// Renders an edge to the viewport using legacy OpenGL. /// - /// + /// /// /// - /// + /// /// - private void RenderWall(LVDCollision col, LVDVector2 p1, LVDVector2 p2, LVDCollisionMaterial mat, Vector2 normal) + private void RenderEdge(LVDCollision collision, LVDVector2 p1, LVDVector2 p2, LVDCollisionAttribute attribute, Vector2 normal) { + Vector2 startPos = (collision.IsDynamic && collision.Dynamic) ? new Vector2(collision.DynamicOffset.X, collision.DynamicOffset.Y) : new Vector2(0.0f, 0.0f); Vector2 v1 = new Vector2(p1.X, p1.Y); Vector2 v2 = new Vector2(p2.X, p2.Y); - Vector2 mid = (v1 + v2) / 2; - Vector2 nrm = mid + normal * 3; + Vector2 mid = (v1 + v2) / 2.0f; + Vector2 nrm = mid + normal * 3.0f; Vector3 p1Color = GetElementColor(p1); Vector3 p2Color = GetElementColor(p2); - if(PropertyGrid.SelectedObject == col) + + if (PropertyGrid.SelectedObject == collision) { p1Color = FlashColor; p2Color = FlashColor; } // material - var materialColor = GetMatlColor(mat); - GL.Color4(materialColor.R / 255f, materialColor.G / 255f, materialColor.B / 255f, 0.75f); + var materialColor = GetMaterialColor(attribute); + GL.Color4(materialColor.R / 255.0f, materialColor.G / 255.0f, materialColor.B / 255.0f, 0.75f); GL.Begin(PrimitiveType.Quads); - GL.Vertex3(p1.X, p1.Y, 0); - GL.Vertex3(p1.X, p1.Y, -PlatformWidth); - GL.Vertex3(p2.X, p2.Y, -PlatformWidth); - GL.Vertex3(p2.X, p2.Y, 0); + GL.Vertex3(p1.X + startPos.X, p1.Y + startPos.Y, 0.0f); + GL.Vertex3(p1.X + startPos.X, p1.Y + startPos.Y, -CollisionDepth); + GL.Vertex3(p2.X + startPos.X, p2.Y + startPos.Y, -CollisionDepth); + GL.Vertex3(p2.X + startPos.X, p2.Y + startPos.Y, 0.0f); GL.End(); - GL.LineWidth(2f); + GL.LineWidth(2.0f); GL.Begin(PrimitiveType.Lines); // point line 1 GL.Color3(p1Color); - GL.Vertex3(v1.X, v1.Y, 0); + GL.Vertex3(v1.X + startPos.X, v1.Y + startPos.Y, 0.0f); GL.Color3(p1Color); - GL.Vertex3(v1.X, v1.Y, -PlatformWidth); + GL.Vertex3(v1.X + startPos.X, v1.Y + startPos.Y, -CollisionDepth); // point line 2 GL.Color3(p2Color); - GL.Vertex3(v2.X, v2.Y, 0); + GL.Vertex3(v2.X + startPos.X, v2.Y + startPos.Y, 0.0f); GL.Color3(p2Color); - GL.Vertex3(v2.X, v2.Y, -PlatformWidth); + GL.Vertex3(v2.X + startPos.X, v2.Y + startPos.Y, -CollisionDepth); // front line GL.Color3(p1Color); - GL.Vertex3(v1.X, v1.Y, 0); + GL.Vertex3(v1.X + startPos.X, v1.Y + startPos.Y , 0.0f); GL.Color3(p2Color); - GL.Vertex3(v2.X, v2.Y, 0); + GL.Vertex3(v2.X + startPos.X, v2.Y + startPos.Y, 0.0f); // back line GL.Color3(p1Color); - GL.Vertex3(v1.X, v1.Y, -PlatformWidth); + GL.Vertex3(v1.X + startPos.X, v1.Y + startPos.Y, -CollisionDepth); GL.Color3(p2Color); - GL.Vertex3(v2.X, v2.Y, -PlatformWidth); + GL.Vertex3(v2.X + startPos.X, v2.Y + startPos.Y, -CollisionDepth); // normal - GL.Color3(GetNormalColor(col, normal, mat)); - GL.Vertex3(mid.X, mid.Y, -PlatformWidth/2); - GL.Color3(GetNormalColor(col, normal, mat)); - GL.Vertex3(nrm.X, nrm.Y, -PlatformWidth/2); + GL.Color3(GetNormalColor(collision, normal, attribute)); + GL.Vertex3(mid.X + startPos.X, mid.Y + startPos.Y, -CollisionDepth / 2.0f); + GL.Color3(GetNormalColor(collision, normal, attribute)); + GL.Vertex3(nrm.X + startPos.X, nrm.Y + startPos.Y, -CollisionDepth / 2.0f); GL.End(); } - /// - /// Renders the bounds using legacy opengl camera, blastzones ect... + /// Renders a rectangular region to the viewport using legacy OpenGL. /// - /// + /// /// - private void RenderBounds(LVDBounds b, Color color) + private void RenderRegion(LVDRegion region, Color color) { - Vector3 sPos = b.UseStartPosition ? new Vector3(b.StartPosition.X, b.StartPosition.Y, b.StartPosition.Z) : new Vector3(0, 0, 0); - GL.Color4(Color.FromArgb(128, color)); - if (PropertyGrid.SelectedObject == b) + + if (PropertyGrid.SelectedObject == region) + { GL.Color3(FlashColor); + } - GL.LineWidth(2); + GL.LineWidth(2.0f); GL.Begin(PrimitiveType.LineLoop); - GL.Vertex3(b.Left + sPos.X, b.Top + sPos.Y, sPos.Z); - GL.Vertex3(b.Right + sPos.X, b.Top + sPos.Y, sPos.Z); - GL.Vertex3(b.Right + sPos.X, b.Bottom + sPos.Y, sPos.Z); - GL.Vertex3(b.Left + sPos.X, b.Bottom + sPos.Y, sPos.Z); + GL.Vertex3(region.Rectangle.Left, region.Rectangle.Top, 0.0f); + GL.Vertex3(region.Rectangle.Right, region.Rectangle.Top, 0.0f); + GL.Vertex3(region.Rectangle.Right, region.Rectangle.Bottom, 0.0f); + GL.Vertex3(region.Rectangle.Left, region.Rectangle.Bottom, 0.0f); GL.End(); } /// - /// Returns color of normal + /// Returns color of the unit normal vector. /// - /// - /// - /// + /// + /// + /// /// - private Color GetNormalColor(LVDCollision c, Vector2 normals, LVDCollisionMaterial material) + private Color GetNormalColor(LVDCollision collision, Vector2 normal, LVDCollisionAttribute attribute) { - float angle = (float)(Math.Atan2(normals.Y, normals.X) * 180 / Math.PI); + float angle = (float)Math.Atan2(normal.Y, normal.X) * 180.0f / (float)Math.PI; - if (c.PassThrough) + // Check edge attributes first, then determine unit normal vector color from the angle of the edge. + if (collision.DropThrough || attribute.DropThrough) + { return Color.FromArgb(128, Color.Yellow); - else if (material.GetFlag(4) && ((angle <= 0 && angle >= -70) || (angle <= -110 && angle >= -180) || angle == 180)) - return Color.FromArgb(128, Color.Purple); - else if ((angle <= 0 && angle >= -70) || (angle <= -110 && angle >= -180) || angle == 180) + } + else if (attribute.RightWallOverride || attribute.LeftWallOverride) + { return Color.FromArgb(128, Color.Lime); - else if (normals.Y < 0) + } + else if (attribute.CeilingOverride) + { return Color.FromArgb(128, Color.Red); - else + } + else if (attribute.FloorOverride || (angle > 40.0f && angle < 140.0f)) + { return Color.FromArgb(128, Color.Cyan); + } + else if (((angle >= 140.0f && angle <= 180.0f) || angle < -110.0f) || (angle <= 40.0f && angle > -70.0f)) + { + return attribute.NoWallJump ? Color.FromArgb(128, Color.Purple) : Color.FromArgb(128, Color.Lime); + } + else if (angle >= -110.0f && angle <= -70.0f) + { + return Color.FromArgb(128, Color.Red); + } + else + { + return Color.FromArgb(128, Color.Black); + } } /// - /// render lvd shape to the viewport + /// Renders an LVD shape to the viewport using legacy OpenGL. /// /// - private void RenderShape(LVDShape shape) + private void RenderShape(LVDShape2 shape) { switch (shape.Type) { - case LVDShapeType.Circle: + case LVDShape2Type.Point: + break; + case LVDShape2Type.Circle: break; - case LVDShapeType.Path: + case LVDShape2Type.Rectangle: + break; + case LVDShape2Type.Path: GL.Color3(Color.Bisque); GL.Begin(PrimitiveType.LineStrip); + foreach (var p in shape.Points) - GL.Vertex3(p.X, p.Y, 0); + { + GL.Vertex3(p.X, p.Y, 0.0f); + } + GL.End(); break; - case LVDShapeType.Point: - break; - case LVDShapeType.Rectangle: - break; } } /// - /// returns color of Collision Material + /// Returns the color of the collision's edge's assigned material. /// - /// + /// /// - private Color GetMatlColor(LVDCollisionMaterial mat) + private Color GetMaterialColor(LVDCollisionAttribute attribute) { - if (PropertyGrid.SelectedObject == mat) - return Color.FromArgb(255, (int)(FlashColor.X * 255), (int)(FlashColor.Y * 255), (int)(FlashColor.Z * 255)); - switch (mat.Physics) + if (PropertyGrid.SelectedObject == attribute) { - case CollisionMatType.Basic: - return Color.AliceBlue; - case CollisionMatType.Brick: - return Color.SaddleBrown; - case CollisionMatType.Cloud: - return Color.FromArgb(0xFF, 0xF6, 0x9A, 0xB0); - case CollisionMatType.Alien: - return Color.DarkGreen; - case CollisionMatType.Cardboard: - return Color.SandyBrown; - case CollisionMatType.Carpet: - return Color.PaleVioletRed; - case CollisionMatType.Electroplankton: - return Color.DarkSeaGreen; - case CollisionMatType.GameWatch: - return Color.LightGray; - case CollisionMatType.Grass: + return Color.FromArgb(255, (int)(FlashColor.X * 255.0f), (int)(FlashColor.Y * 255.0f), (int)(FlashColor.Z * 255.0f)); + } + + switch (attribute.Type) + { + case LVDCollisionMaterialType.Basic: + return Color.WhiteSmoke; + case LVDCollisionMaterialType.Rock: + return Color.SlateGray; + case LVDCollisionMaterialType.Grass: return Color.ForestGreen; - case CollisionMatType.Grate: - return Color.Gray; - case CollisionMatType.Hazard2SSEOnly: - return Color.Gray; - case CollisionMatType.Hazard3SSEOnly: - return Color.Gray; - case CollisionMatType.HeavyMetal: + case LVDCollisionMaterialType.Soil: + return Color.Sienna; + case LVDCollisionMaterialType.Wood: + return Color.BurlyWood; + case LVDCollisionMaterialType.LightMetal: return Color.LightGray; - case CollisionMatType.Homerun: - return Color.LawnGreen; - case CollisionMatType.Hurt: - return Color.IndianRed; - case CollisionMatType.Ice: + case LVDCollisionMaterialType.HeavyMetal: + return Color.DarkGray; + case LVDCollisionMaterialType.Carpet: + return Color.Tomato; + case LVDCollisionMaterialType.Slimy: + return Color.Goldenrod; + case LVDCollisionMaterialType.Creature: + return Color.DarkOliveGreen; + case LVDCollisionMaterialType.Shoal: + return Color.LightSkyBlue; + case LVDCollisionMaterialType.Soft: + return Color.LightPink; + case LVDCollisionMaterialType.Slippery: + return Color.LightGreen; + case LVDCollisionMaterialType.Snow: + return Color.Snow; + case LVDCollisionMaterialType.Ice: return Color.CornflowerBlue; - case CollisionMatType.LightMetal: - return Color.LightGray; - case CollisionMatType.MasterFortress: + case LVDCollisionMaterialType.GameWatch: + return Color.DarkKhaki; + case LVDCollisionMaterialType.Oil: return Color.DarkSlateGray; - case CollisionMatType.NES8Bit: + case LVDCollisionMaterialType.Cardboard: + return Color.Peru; + case LVDCollisionMaterialType.Damage1: + case LVDCollisionMaterialType.Damage2: + case LVDCollisionMaterialType.Damage3: return Color.Gray; - case CollisionMatType.Oil: - return Color.DarkSlateGray; - case CollisionMatType.Rock: - return Color.RosyBrown; - case CollisionMatType.Sand: + case LVDCollisionMaterialType.Hanenbow: + return Color.DarkSeaGreen; + case LVDCollisionMaterialType.Cloud: + return Color.FromArgb(0xFF, 0xF6, 0x9A, 0xB0); + case LVDCollisionMaterialType.Subspace: + return Color.PaleVioletRed; + case LVDCollisionMaterialType.Brick: + return Color.DarkSalmon; + case LVDCollisionMaterialType.NoAttr: + return Color.AliceBlue; + case LVDCollisionMaterialType.Famicom: + return Color.OrangeRed; + case LVDCollisionMaterialType.WireNetting: + return Color.DimGray; + case LVDCollisionMaterialType.Sand: return Color.SandyBrown; - case CollisionMatType.Snow: - return Color.LightBlue; - case CollisionMatType.Soft: - return Color.LightPink; - case CollisionMatType.Soil: - return Color.Brown; - case CollisionMatType.SpikesTargetTest: + case LVDCollisionMaterialType.Homerun: + return Color.Gray; + case LVDCollisionMaterialType.AsaseEarth: + return Color.LightSkyBlue; + case LVDCollisionMaterialType.Death: return Color.IndianRed; - case CollisionMatType.Wood: - return Color.Brown; + case LVDCollisionMaterialType.BoxingRing: + return Color.DeepSkyBlue; + case LVDCollisionMaterialType.Glass: + return Color.GhostWhite; + case LVDCollisionMaterialType.SlipDx: + return Color.LightSlateGray; + case LVDCollisionMaterialType.SpPoison: + return Color.MediumOrchid; + case LVDCollisionMaterialType.SpFlame: + return Color.DarkOrange; + case LVDCollisionMaterialType.SpElectricShock: + return Color.Yellow; + case LVDCollisionMaterialType.SpSleep: + return Color.Violet; + case LVDCollisionMaterialType.SpFreezing: + return Color.RoyalBlue; + case LVDCollisionMaterialType.SpAdhesion: + return Color.FromArgb(0xFF, 0x70, 0x64, 0x4A); + case LVDCollisionMaterialType.IceNoSlip: + return Color.CornflowerBlue; + case LVDCollisionMaterialType.CloudNoThrough: + return Color.FromArgb(0xFF, 0xF6, 0x9A, 0xB0); + case LVDCollisionMaterialType.Metaverse: + return Color.Crimson; default: return Color.Black; } @@ -859,9 +1154,13 @@ private Color GetMatlColor(LVDCollisionMaterial mat) private Vector3 GetElementColor(object o) { if (PropertyGrid.SelectedObject == o) + { return (FlashColor); + } else - return new Vector3(0f, 0f, 0f); + { + return new Vector3(0.0f, 0.0f, 0.0f); + } } #endregion } diff --git a/StudioSB/IO/Formats/IO_SSF.cs b/StudioSB/IO/Formats/IO_SSF.cs index d7cc519..25451fc 100644 --- a/StudioSB/IO/Formats/IO_SSF.cs +++ b/StudioSB/IO/Formats/IO_SSF.cs @@ -7,89 +7,107 @@ public class IO_SSF /// /// /// - /// + /// /// - public static void Export(LevelData lvd, string filePath) + public static void Export(LevelData levelData, string filePath) { SSF ssf = new SSF(); - foreach(var v in lvd.Collisions) + foreach (var collision in levelData.Collisions) { var g = new SSFGroup(); ssf.Groups.Add(g); - g.Name = v.EntryLabel; - g.Bone = v.BoneName; - foreach(var x in v.Vertices) - g.Vertices.Add(new SSFVertex() { X = x.X, Y = x.Y }); - for(int i = 0; i < v.Materials.Count; i++) + g.Name = collision.DynamicName; + g.JointName = collision.JointName; + + foreach (var v in collision.Vertices) + { + g.Vertices.Add(new SSFVertex() { X = v.X, Y = v.Y }); + } + + for (int i = 0; i < collision.Attributes.Count; i++) { - g.Lines.Add(new SSFLine() { + g.Edges.Add(new SSFEdge() { Vertex1 = i, Vertex2 = i + 1, - Material = v.Materials[i].Physics.ToString(), - Flags = (v.Materials[i].LeftLedge ? SSFLineFlag.LeftLedge : 0) | - (v.Materials[i].RightLedge ? SSFLineFlag.RightLedge : 0) | - (v.PassThrough ? SSFLineFlag.DropThrough : 0) + Material = collision.Attributes[i].Type.ToString(), + Flags = (collision.Attributes[i].Unpaintable ? SSFEdgeFlags.Unpaintable : SSFEdgeFlags.None) | + (collision.Attributes[i].RightWallOverride ? SSFEdgeFlags.RightWallOverride : SSFEdgeFlags.None) | + (collision.Attributes[i].LeftWallOverride ? SSFEdgeFlags.LeftWallOverride : SSFEdgeFlags.None) | + (collision.Attributes[i].CeilingOverride ? SSFEdgeFlags.CeilingOverride : SSFEdgeFlags.None) | + (collision.Attributes[i].FloorOverride ? SSFEdgeFlags.FloorOverride : SSFEdgeFlags.None) | + (collision.Attributes[i].NoWallJump ? SSFEdgeFlags.NoWallJump : SSFEdgeFlags.None) | + (collision.Attributes[i].DropThrough ? SSFEdgeFlags.DropThrough : SSFEdgeFlags.None) | + (collision.Attributes[i].LeftLedge ? SSFEdgeFlags.LeftLedge : SSFEdgeFlags.None) | + (collision.Attributes[i].RightLedge ? SSFEdgeFlags.RightLedge : SSFEdgeFlags.None) | + (collision.Attributes[i].IgnoreLinkFromLeft ? SSFEdgeFlags.IgnoreLinkFromLeft : SSFEdgeFlags.None) | + (collision.Attributes[i].Supersoft ? SSFEdgeFlags.Supersoft : SSFEdgeFlags.None) | + (collision.Attributes[i].IgnoreLinkFromRight ? SSFEdgeFlags.IgnoreLinkFromRight : SSFEdgeFlags.None), }); } } - foreach (var v in lvd.BlastZoneBounds) + int index = 0; + + foreach (var v in levelData.StartPositions) { ssf.Points.Add(new SSFPoint() { - Tag = "BlastStart", - X = v.Left, - Y = v.Top + Tag = "StartPosition" + index++, + X = v.Position.X, + Y = v.Position.Y }); + } + + index = 0; + + foreach (var v in levelData.RestartPositions) + { ssf.Points.Add(new SSFPoint() { - Tag = "BlastEnd", - X = v.Right, - Y = v.Bottom + Tag = "RestartPosition" + index++, + X = v.Position.X, + Y = v.Position.Y }); } - foreach (var v in lvd.CameraBounds) + index = 0; + + foreach (var v in levelData.CameraRegions) { ssf.Points.Add(new SSFPoint() { - Tag = "CameraStart", - X = v.Left, - Y = v.Top + Tag = "CameraRegionStart" + index++, + X = v.Rectangle.Left, + Y = v.Rectangle.Top }); ssf.Points.Add(new SSFPoint() { - Tag = "CameraEnd", - X = v.Right, - Y = v.Bottom + Tag = "CameraRegionEnd" + index++, + X = v.Rectangle.Right, + Y = v.Rectangle.Bottom }); } - int sIndex = 0; - foreach (var v in lvd.Spawns) + index = 0; + + foreach (var v in levelData.DeathRegions) { ssf.Points.Add(new SSFPoint() { - Tag = "Spawn" + sIndex++, - X = v.X, - Y = v.Y + Tag = "DeathRegionStart" + index++, + X = v.Rectangle.Left, + Y = v.Rectangle.Top }); - } - sIndex = 0; - foreach (var v in lvd.Respawns) - { ssf.Points.Add(new SSFPoint() { - Tag = "Respawn" + sIndex++, - X = v.X, - Y = v.Y + Tag = "DeathRegionEnd" + index++, + X = v.Rectangle.Right, + Y = v.Rectangle.Bottom }); } ssf.Save(filePath); } } - - } diff --git a/StudioSB/IO/Formats/SSF.cs b/StudioSB/IO/Formats/SSF.cs index 7acc0af..c7dbc3e 100644 --- a/StudioSB/IO/Formats/SSF.cs +++ b/StudioSB/IO/Formats/SSF.cs @@ -6,11 +6,21 @@ namespace StudioSB.IO.Formats { [Flags] - public enum SSFLineFlag + public enum SSFEdgeFlags { - RightLedge, - LeftLedge, - DropThrough + None = 0x0, + Unpaintable = 0x20, + RightWallOverride = 0x100, + LeftWallOverride = 0x200, + CeilingOverride = 0x400, + FloorOverride = 0x800, + NoWallJump = 0x1000, + DropThrough = 0x2000, + LeftLedge = 0x4000, + RightLedge = 0x8000, + IgnoreLinkFromLeft = 0x10000, + Supersoft = 0x20000, + IgnoreLinkFromRight = 0x40000, } [Serializable] @@ -48,17 +58,17 @@ public class SSFPoint public class SSFGroup { public string Name; - public string Bone; - public List Lines = new List(); + public string JointName; public List Vertices = new List(); + public List Edges = new List(); } - public class SSFLine + public class SSFEdge { public int Vertex1; public int Vertex2; public string Material; - public SSFLineFlag Flags; + public SSFEdgeFlags Flags = SSFEdgeFlags.None; public string Tags; } diff --git a/StudioSB/Scenes/LVD/LVDBase.cs b/StudioSB/Scenes/LVD/LVDBase.cs new file mode 100644 index 0000000..b0e9f9d --- /dev/null +++ b/StudioSB/Scenes/LVD/LVDBase.cs @@ -0,0 +1,176 @@ +using StudioSB.Tools; +using System.ComponentModel; + +namespace StudioSB.Scenes.LVD +{ + public class LVDBase + { + [ReadOnly(true), Category("Version")] + public byte BaseVersion { get; internal set; } = 4; + + [Category("Base"), TypeConverter(typeof(ExpandableObjectConverter))] + public LVDMetaInfo MetaInfo { get; set; } = new LVDMetaInfo(); + + [Category("Base")] + public string DynamicName { get; set; } + + [Category("Base"), TypeConverter(typeof(ExpandableObjectConverter))] + public LVDVector3 DynamicOffset { get; set; } = new LVDVector3(0.0f, 0.0f, 0.0f); + + [Category("Base")] + public bool IsDynamic { get; set; } + + [Category("Base")] + public uint InstanceID { get; set; } + + [Category("Base"), TypeConverter(typeof(ExpandableObjectConverter))] + public LVDVector3 InstanceOffset { get; set; } = new LVDVector3(0.0f, 0.0f, 0.0f); + + [Category("Base")] + public int JointIndex { get; set; } + + [Category("Base")] + public string JointName { get; set; } + + public virtual void Read(BinaryReaderExt reader) + { + BaseVersion = reader.ReadByte(); + + MetaInfo.Read(reader); + + reader.Skip(1); + DynamicName = reader.ReadString(); + reader.Skip(0x40 - (uint)DynamicName.Length - 1); + + if (BaseVersion < 2) + { + return; + } + + DynamicOffset.Read(reader); + + if (BaseVersion < 3) + { + return; + } + + IsDynamic = reader.ReadBoolean(); + + reader.Skip(1); + InstanceID = reader.ReadUInt32(); + + InstanceOffset.Read(reader); + + if (BaseVersion < 4) + { + return; + } + + JointIndex = reader.ReadInt32(); + + reader.Skip(1); + JointName = reader.ReadString(); + reader.Skip(0x40 - (uint)JointName.Length - 1); + } + + public virtual void Write(BinaryWriterExt writer) + { + writer.Write(BaseVersion); + + MetaInfo.Write(writer); + + writer.Write((byte)1); + writer.Write(DynamicName); + writer.Write(new byte[0x40 - DynamicName.Length - 1]); + + if (BaseVersion < 2) + { + return; + } + + DynamicOffset.Write(writer); + + if (BaseVersion < 3) + { + return; + } + + writer.Write(IsDynamic); + + writer.Write((byte)1); + writer.Write(InstanceID); + + InstanceOffset.Write(writer); + + if (BaseVersion < 4) + { + return; + } + + writer.Write(JointIndex); + + writer.Write((byte)1); + writer.Write(JointName); + writer.Write(new byte[0x40 - JointName.Length - 1]); + } + } + + public class LVDMetaInfo + { + [ReadOnly(true)] + public byte Version { get; internal set; } = 1; + + [ReadOnly(true), TypeConverter(typeof(ExpandableObjectConverter))] + public LVDVersionInfo VersionInfo { get; internal set; } = new LVDVersionInfo(); + + public string Name { get; set; } + + public void Read(BinaryReaderExt reader) + { + Version = reader.ReadByte(); + + VersionInfo.Read(reader); + + reader.Skip(1); + Name = reader.ReadString(); + reader.Skip(0x38 - (uint)Name.Length - 1); + } + + public void Write(BinaryWriterExt writer) + { + writer.Write(Version); + + VersionInfo.Write(writer); + + writer.Write((byte)1); + writer.Write(Name); + writer.Write(new byte[0x38 - Name.Length - 1]); + } + } + + public class LVDVersionInfo + { + [ReadOnly(true)] + public byte Version { get; internal set; } = 1; + + [ReadOnly(true)] + public uint EditorVersion { get; internal set; } + + [ReadOnly(true)] + public uint FormatVersion { get; internal set; } + + public void Read(BinaryReaderExt reader) + { + Version = reader.ReadByte(); + EditorVersion = reader.ReadUInt32(); + FormatVersion = reader.ReadUInt32(); + } + + public void Write(BinaryWriterExt writer) + { + writer.Write(Version); + writer.Write(EditorVersion); + writer.Write(FormatVersion); + } + } +} diff --git a/StudioSB/Scenes/LVD/LVDBounds.cs b/StudioSB/Scenes/LVD/LVDBounds.cs deleted file mode 100644 index 7cd3118..0000000 --- a/StudioSB/Scenes/LVD/LVDBounds.cs +++ /dev/null @@ -1,34 +0,0 @@ -using StudioSB.Tools; - -namespace StudioSB.Scenes.LVD -{ - public class LVDBounds : LVDEntry - { - public float Left { get; set; } - public float Right { get; set; } - public float Top { get; set; } - public float Bottom { get; set; } - - public override void Read(BinaryReaderExt r) - { - base.Read(r); - - r.Skip(1); - Left = r.ReadSingle(); - Right = r.ReadSingle(); - Top = r.ReadSingle(); - Bottom = r.ReadSingle(); - } - - public override void Write(BinaryWriterExt writer) - { - base.Write(writer); - - writer.Write((byte)1); - writer.Write(Left); - writer.Write(Right); - writer.Write(Top); - writer.Write(Bottom); - } - } -} diff --git a/StudioSB/Scenes/LVD/LVDCollision.cs b/StudioSB/Scenes/LVD/LVDCollision.cs index add844e..79eae7a 100644 --- a/StudioSB/Scenes/LVD/LVDCollision.cs +++ b/StudioSB/Scenes/LVD/LVDCollision.cs @@ -1,75 +1,19 @@ using StudioSB.Tools; -using System; using System.Collections.Generic; using System.ComponentModel; namespace StudioSB.Scenes.LVD { - public class LVDVector2 + public class LVDCollision : LVDBase { - public float X { get; set; } + [ReadOnly(true), Category("Version")] + public byte Version { get; internal set; } = 4; - public float Y { get; set; } + [Category("CollisionFlags")] + public bool Dynamic { get; set; } = false; - public LVDVector2(float x, float y) - { - X = x; - Y = y; - } - - public override string ToString() - { - return $"({X}, {Y})"; - } - - public LVDVector2 Normalized() - { - float length = (float)Math.Sqrt(X * X + Y * Y); - return new LVDVector2(X / length, Y / length); - } - - public static LVDVector2 GenerateNormal(LVDVector2 v1, LVDVector2 v2) - { - LVDVector2 normal = new LVDVector2(v2.Y - v1.Y, v2.X - v1.X).Normalized(); - normal.X *= -1; - return normal; - } - } - - public class LVDVector3 - { - public float X { get; set; } - - public float Y { get; set; } - - public float Z { get; set; } - - public LVDVector3(float x, float y, float z) - { - X = x; - Y = y; - Z = z; - } - - public override string ToString() - { - return $"({X}, {Y}, {Z})"; - } - } - - public class LVDCollision : LVDEntry - { - [Category("Collision")] - public bool Flag1 { get; set; } = false; - - [Category("Collision")] - public bool Rigged { get; set; } = false; - - [Category("Collision")] - public bool Flag3 { get; set; } = false; - - [Category("Collision")] - public bool PassThrough { get; set; } = false; + [Category("CollisionFlags")] + public bool DropThrough { get; set; } = false; [Category("Collision")] public List Vertices { get; set; } = new List(); @@ -81,94 +25,120 @@ public class LVDCollision : LVDEntry public List Cliffs { get; set; } = new List(); [Category("Collision")] - public List Materials { get; set; } = new List(); - + public List Attributes { get; set; } = new List(); + [Category("Collision")] - public List Curves = new List(); + public List SpiritsFloors { get; set; } = new List(); - public void Read(BinaryReaderExt r, int VersionMinor) + public override void Read(BinaryReaderExt reader) { - base.Read(r); + Version = reader.ReadByte(); - Flag1 = r.ReadBoolean(); - Rigged = r.ReadBoolean(); - Flag3 = r.ReadBoolean(); - PassThrough = r.ReadBoolean(); + if (Version < 2) + { + MetaInfo.Read(reader); + } + else + { + base.Read(reader); + } + + reader.Skip(1); + Dynamic = reader.ReadBoolean(); + reader.Skip(1); + DropThrough = reader.ReadBoolean(); - r.ReadByte(); - int vertCount = r.ReadInt32(); - for (int i = 0; i < vertCount; i++) + reader.Skip(1); + uint vertexCount = reader.ReadUInt32(); + for (uint i = 0; i < vertexCount; i++) { - r.ReadByte(); - Vertices.Add(new LVDVector2(r.ReadSingle(), r.ReadSingle())); + LVDVector2 vertex = new LVDVector2(0.0f, 0.0f); + + vertex.Read(reader); + Vertices.Add(vertex); } - - r.ReadByte(); - int normalCount = r.ReadInt32(); - for (int i = 0; i < normalCount; i++) + + reader.Skip(1); + uint normalCount = reader.ReadUInt32(); + for (uint i = 0; i < normalCount; i++) { - r.ReadByte(); - Normals.Add(new LVDVector2(r.ReadSingle(), r.ReadSingle())); + LVDVector2 normal = new LVDVector2(0.0f, 0.0f); + + normal.Read(reader); + Normals.Add(normal); } - r.ReadByte(); - int cliffCount = r.ReadInt32(); - for (int i = 0; i < cliffCount; i++) + reader.Skip(1); + uint cliffCount = reader.ReadUInt32(); + for (uint i = 0; i < cliffCount; i++) { - var cliff = new LVDCollisionCliff(); - cliff.Read(r); + LVDCollisionCliff cliff = new LVDCollisionCliff(); + + cliff.Read(reader); Cliffs.Add(cliff); } - - r.ReadByte(); - int materialCount = r.ReadInt32(); - for (int i = 0; i < materialCount; i++) + + if (Version < 3) { - var material = new LVDCollisionMaterial(); - material.Read(r); - Materials.Add(material); + return; } - // Ultimate Only? + reader.Skip(1); + uint attributeCount = reader.ReadUInt32(); + for (uint i = 0; i < attributeCount; i++) + { + LVDCollisionAttribute attribute = new LVDCollisionAttribute(); - if(VersionMinor > 10) + attribute.Read(reader); + Attributes.Add(attribute); + } + + if (Version < 4) { - r.ReadByte(); - var vecCount = r.ReadInt32(); - for(int i = 0; i < vecCount; i++) - { - var vec = new LVDCollisionCurve(); - vec.Read(r); - Curves.Add(vec); - } + return; + } + + reader.Skip(1); + uint spiritsFloorCount = reader.ReadUInt32(); + for (uint i = 0; i < spiritsFloorCount; i++) + { + LVDCollisionSpiritsFloor spiritsFloor = new LVDCollisionSpiritsFloor(); + + spiritsFloor.Read(reader); + SpiritsFloors.Add(spiritsFloor); } } - public void Write(BinaryWriterExt writer, int VersionMinor) + public override void Write(BinaryWriterExt writer) { - base.Write(writer); + writer.Write(Version); - writer.Write(Flag1); - writer.Write(Rigged); - writer.Write(Flag3); - writer.Write(PassThrough); + if (Version < 2) + { + MetaInfo.Write(writer); + } + else + { + base.Write(writer); + } + + writer.Write((byte)0); + writer.Write(Dynamic); + writer.Write((byte)0); + writer.Write(DropThrough); writer.Write((byte)1); writer.Write(Vertices.Count); - foreach(var v in Vertices) + foreach (var v in Vertices) { - writer.Write((byte)1); - writer.Write(v.X); - writer.Write(v.Y); + v.Write(writer); } writer.Write((byte)1); writer.Write(Normals.Count); foreach (var v in Normals) { - writer.Write((byte)1); - writer.Write(v.X); - writer.Write(v.Y); + v.Write(writer); } writer.Write((byte)1); @@ -178,21 +148,28 @@ public void Write(BinaryWriterExt writer, int VersionMinor) v.Write(writer); } + if (Version < 3) + { + return; + } + writer.Write((byte)1); - writer.Write(Materials.Count); - foreach (var v in Materials) + writer.Write(Attributes.Count); + foreach (var v in Attributes) { v.Write(writer); } - - if (VersionMinor > 10) - { - writer.Write((byte)1); - writer.Write(Curves.Count); - foreach (var v in Curves) - { - v.Write(writer); - } + + if (Version < 4) + { + return; + } + + writer.Write((byte)1); + writer.Write(SpiritsFloors.Count); + foreach (var v in SpiritsFloors) + { + v.Write(writer); } } } diff --git a/StudioSB/Scenes/LVD/LVDCollisionAttribute.cs b/StudioSB/Scenes/LVD/LVDCollisionAttribute.cs new file mode 100644 index 0000000..c08d8ee --- /dev/null +++ b/StudioSB/Scenes/LVD/LVDCollisionAttribute.cs @@ -0,0 +1,191 @@ +using StudioSB.Tools; +using System.ComponentModel; + +namespace StudioSB.Scenes.LVD +{ + public enum LVDCollisionMaterialType : uint + { + Basic = 0x00, // + Rock = 0x01, // + Grass = 0x02, // Produces a grass shard effect. + Soil = 0x03, // Produces a soil particle effect when landing. + Wood = 0x04, // + LightMetal = 0x05, // Internally "Iron" + HeavyMetal = 0x06, // Internally "NibuIron" + Carpet = 0x07, // + Slimy = 0x08, // Internally "Numenume" + Creature = 0x09, // + Shoal = 0x0A, // Internally "Asase." Produces a water splash effect. + Soft = 0x0B, // + Slippery = 0x0C, // Internally "Turuturu." Friction value of 0.1. + Snow = 0x0D, // + Ice = 0x0E, // Friction value of 0.2. Produces an ice particle effect when landing. + GameWatch = 0x0F, // Used on the Flat Zone X stage. + Oil = 0x10, // Used on the Flat Zone X stage on the Helmet game. Friction value of 0.1. + Cardboard = 0x11, // Internally "Danbouru" + Damage1 = 0x12, // "damage_id" value of 1. + Damage2 = 0x13, // "damage_id" value of 2. + Damage3 = 0x14, // "damage_id" value of 3. + Hanenbow = 0x15, // Used on the Hanenbow stage. + Cloud = 0x16, // Force-enables supersoft properties. + Subspace = 0x17, // Internally "Akuukan" + Brick = 0x18, // + NoAttr = 0x19, // Same as the "Basic" material but does not produce any special graphical or sound effects. + Famicom = 0x1A, // Used on the Mario Bros. stage. + WireNetting = 0x1B, // + Sand = 0x1C, // Produces a sand particle effect when landing. + Homerun = 0x1D, // + AsaseEarth = 0x1E, // + Death = 0x1F, // "damage_id" value of 4. + BoxingRing = 0x20, // Used on the Boxing Ring stage. + Glass = 0x21, // + SlipDx = 0x22, // Used for slippery surfaces on newly-returning Melee stages. Friction value of 0.4. + SpPoison = 0x23, // Used for environmental floor hazards in spirit battles. + SpFlame = 0x24, // Used for environmental floor hazards in spirit battles. + SpElectricShock = 0x25, // Used for environmental floor hazards in spirit battles. + SpSleep = 0x26, // Used for environmental floor hazards in spirit battles. + SpFreezing = 0x27, // Used for environmental floor hazards in spirit battles. Same as the "Ice" material. + SpAdhesion = 0x28, // Used for environmental floor hazards in spirit battles. + IceNoSlip = 0x29, // Same as the "Ice" material but does not have any reduced traction. + CloudNoThrough = 0x2A, // Same as the "Cloud" material but does not force-enable supersoft properties. + Metaverse = 0x2B, // Internally "Jack_Mementoes." Produces the Metaverse splash effect. + } + + public class LVDCollisionAttribute + { + [ReadOnly(true), Category("Version")] + public byte Version { get; internal set; } = 1; + + private uint[] MaterialData = new uint[3]; + + [Category("Material")] + public LVDCollisionMaterialType Type + { + get { return (LVDCollisionMaterialType)MaterialData[0]; } + set { MaterialData[0] = (uint)value; } + } + + [Category("Attributes")] + public bool Unpaintable + { + get { return GetFlag(5); } + set { SetFlag(5, value); } + } + + [Category("Attributes")] + public bool RightWallOverride + { + get { return GetFlag(8); } + set { SetFlag(8, value); } + } + + [Category("Attributes")] + public bool LeftWallOverride + { + get { return GetFlag(9); } + set { SetFlag(9, value); } + } + + [Category("Attributes")] + public bool CeilingOverride + { + get { return GetFlag(10); } + set { SetFlag(10, value); } + } + + [Category("Attributes")] + public bool FloorOverride + { + get { return GetFlag(11); } + set { SetFlag(11, value); } + } + + [Category("Attributes")] + public bool NoWallJump + { + get { return GetFlag(12); } + set { SetFlag(12, value); } + } + + [Category("Attributes")] + public bool DropThrough + { + get { return GetFlag(13); } + set { SetFlag(13, value); } + } + + [Category("Attributes")] + public bool LeftLedge + { + get { return GetFlag(14); } + set { SetFlag(14, value); } + } + + [Category("Attributes")] + public bool RightLedge + { + get { return GetFlag(15); } + set { SetFlag(15, value); } + } + + [Category("Attributes")] + public bool IgnoreLinkFromLeft + { + get { return GetFlag(16); } + set { SetFlag(16, value); } + } + + [Category("Attributes")] + public bool Supersoft + { + get { return GetFlag(17); } + set { SetFlag(17, value); } + } + + [Category("Attributes")] + public bool IgnoreLinkFromRight + { + get { return GetFlag(18); } + set { SetFlag(18, value); } + } + + public bool GetFlag(int n) + { + return (MaterialData[2] & 1 << n) != 0; + } + + public void SetFlag(int flag, bool value) + { + uint mask = (uint)(1 << flag); + + if (value) + { + MaterialData[2] |= mask; + } + else + { + MaterialData[2] &= ~mask; + } + } + + public void Read(BinaryReaderExt reader) + { + Version = reader.ReadByte(); + + for (int i = 0; i < MaterialData.Length; i++) + { + MaterialData[i] = reader.ReadUInt32(); + } + } + + public void Write(BinaryWriterExt writer) + { + writer.Write(Version); + + for (int i = 0; i < MaterialData.Length; i++) + { + writer.Write(MaterialData[i]); + } + } + } +} diff --git a/StudioSB/Scenes/LVD/LVDCollisionCliff.cs b/StudioSB/Scenes/LVD/LVDCollisionCliff.cs index c70a67b..b8b51ff 100644 --- a/StudioSB/Scenes/LVD/LVDCollisionCliff.cs +++ b/StudioSB/Scenes/LVD/LVDCollisionCliff.cs @@ -1,34 +1,61 @@ using StudioSB.Tools; +using System.ComponentModel; namespace StudioSB.Scenes.LVD { - public class LVDCollisionCliff : LVDEntry + public class LVDCollisionCliff : LVDBase { - public LVDVector2 Position { get; set; } = new LVDVector2(0, 0); + [ReadOnly(true), Category("Version")] + public byte Version { get; internal set; } = 3; - public float Angle { get; set; } = 0; + [Category("Values"), TypeConverter(typeof(ExpandableObjectConverter))] + public LVDVector2 Position { get; set; } = new LVDVector2(0.0f, 0.0f); - public int LineIndex { get; set; } = 0; + [Category("Values")] + public float Lr { get; set; } - public override void Read(BinaryReaderExt r) + [Category("Values")] + public int LineIndex { get; set; } + + public override void Read(BinaryReaderExt reader) { - base.Read(r); - - r.Skip(1); - Position.X = r.ReadSingle(); - Position.Y = r.ReadSingle(); - Angle = r.ReadSingle(); - LineIndex = r.ReadInt32(); + Version = reader.ReadByte(); + + if (Version > 1) + { + base.Read(reader); + } + + Position.Read(reader); + + Lr = reader.ReadSingle(); + + if (Version < 3) + { + return; + } + + LineIndex = reader.ReadInt32(); } public override void Write(BinaryWriterExt writer) { - base.Write(writer); + writer.Write(Version); + + if (Version > 1) + { + base.Write(writer); + } + + Position.Write(writer); + + writer.Write(Lr); + + if (Version < 3) + { + return; + } - writer.Write((byte)1); - writer.Write(Position.X); - writer.Write(Position.Y); - writer.Write(Angle); writer.Write(LineIndex); } } diff --git a/StudioSB/Scenes/LVD/LVDCollisionCurve.cs b/StudioSB/Scenes/LVD/LVDCollisionCurve.cs deleted file mode 100644 index 15286d3..0000000 --- a/StudioSB/Scenes/LVD/LVDCollisionCurve.cs +++ /dev/null @@ -1,60 +0,0 @@ -using StudioSB.Tools; - -namespace StudioSB.Scenes.LVD -{ - public class LVDCollisionCurve : LVDEntry - { - public int ID { get; set; } - - public string Name { get; set; } - - public float X { get; set; } = 1; - - public float Y { get; set; } = 1; - - public float Z { get; set; } = 1; - - public float W { get; set; } = 1; - - public int Unknown1 { get; set; } = 0; - - public int Unknown2 { get; set; } = 0; - - public override void Read(BinaryReaderExt r) - { - base.Read(r); - - ID = r.ReadInt32(); - - r.Skip(1); - Name = r.ReadString(0x40); - - X = r.ReadSingle(); - Y = r.ReadSingle(); - Z = r.ReadSingle(); - W = r.ReadSingle(); - - Unknown1 = r.ReadInt32(); - Unknown2 = r.ReadInt32(); - } - - public override void Write(BinaryWriterExt writer) - { - base.Write(writer); - - writer.Write(ID); - - writer.Write((byte)1); - writer.Write(Name.ToCharArray()); - writer.Write(new byte[0x40 - Name.Length]); - - writer.Write(X); - writer.Write(Y); - writer.Write(Z); - writer.Write(W); - - writer.Write(Unknown1); - writer.Write(Unknown2); - } - } -} diff --git a/StudioSB/Scenes/LVD/LVDCollisionMaterial.cs b/StudioSB/Scenes/LVD/LVDCollisionMaterial.cs deleted file mode 100644 index 1df422a..0000000 --- a/StudioSB/Scenes/LVD/LVDCollisionMaterial.cs +++ /dev/null @@ -1,97 +0,0 @@ -using StudioSB.Tools; - -namespace StudioSB.Scenes.LVD -{ - public enum CollisionMatType : byte - { - Basic = 0x00, // - Rock = 0x01, // - Grass = 0x02, //Increased traction (1.5) - Soil = 0x03, // - Wood = 0x04, // - LightMetal = 0x05, //"Iron" internally. - HeavyMetal = 0x06, //"NibuIron" (Iron2) internally. - Carpet = 0x07, //Used for Delfino Plaza roof things - Alien = 0x08, //"NumeNume" (squelch sound) internally. Used on Brinstar - MasterFortress = 0x09, //"Creature" internally. - WaterShallow = 0x0a, //"Asase" (shallows) internally. Used for Delfino Plaza shallow water - Soft = 0x0b, //Used on Woolly World - TuruTuru = 0x0c, //Reduced traction (0.1). Unknown meaning and use - Snow = 0x0d, // - Ice = 0x0e, //Reduced traction (0.2). Used on P. Stadium 2 ice form - GameWatch = 0x0f, //Used on Flat Zone - Oil = 0x10, //Reduced traction (0.1). Used for Flat Zone oil spill (presumably; not found in any collisions) - Cardboard = 0x11, //"Danbouru" (corrugated cardboard) internally. Used on Paper Mario - SpikesTargetTest = 0x12, //Unknown. From Brawl, and appears to still be hazard-related but is probably not functional - Hazard2SSEOnly = 0x13, //See above - Hazard3SSEOnly = 0x14, //See above - Electroplankton = 0x15, //"ElectroP" internally. Not known to be used anywhere in this game - Cloud = 0x16, //Used on Skyworld, Magicant - Subspace = 0x17, //"Akuukan" (subspace) internally. Not known to be used anywhere in this game - Brick = 0x18, //Used on Skyworld, Gerudo V., Smash Run - Unknown1 = 0x19, //Unknown. From Brawl - NES8Bit = 0x1a, //"Famicom" internally. Not known to be used anywhere in this game - Grate = 0x1b, //Used on Delfino and P. Stadium 2 - Sand = 0x1c, // - Homerun = 0x1d, //From Brawl, may not be functional - WaterNoSplash = 0x1e, //From Brawl, may not be functional - Hurt = 0x1f, //Takes hitbox data from stdat. Used for Cave and M. Fortress Danger Zones - Unknown2 = 0x20 //Unknown. Uses bomb SFX? - } - - public class LVDCollisionMaterial - { - private byte[] MaterialData = new byte[0xC]; - - public CollisionMatType Physics - { - get { return (CollisionMatType)MaterialData[3]; } - set { MaterialData[3] = (byte)value; } - } - - public bool LeftLedge - { - get { return GetFlag(6); } - set { SetFlag(6, value); } - } - - public bool RightLedge - { - get { return GetFlag(7); } - set { SetFlag(7, value); } - } - - public bool NoWallJump - { - get { return GetFlag(4); } - set { SetFlag(4, value); } - } - - public bool GetFlag(int n) - { - return ((MaterialData[10] & (1 << n)) != 0); - } - - public void SetFlag(int flag, bool value) - { - byte mask = (byte)(1 << flag); - bool isSet = (MaterialData[10] & mask) != 0; - if (value) - MaterialData[10] |= mask; - else - MaterialData[10] &= (byte)~mask; - } - - public void Read(BinaryReaderExt r) - { - r.ReadByte(); - MaterialData = r.ReadBytes(0xC); - } - - public void Write(BinaryWriterExt writer) - { - writer.Write((byte)1); - writer.Write(MaterialData); - } - } -} diff --git a/StudioSB/Scenes/LVD/LVDCollisionSpiritsFloor.cs b/StudioSB/Scenes/LVD/LVDCollisionSpiritsFloor.cs new file mode 100644 index 0000000..cbbcc18 --- /dev/null +++ b/StudioSB/Scenes/LVD/LVDCollisionSpiritsFloor.cs @@ -0,0 +1,85 @@ +using StudioSB.Tools; +using System.ComponentModel; + +namespace StudioSB.Scenes.LVD +{ + public class LVDCollisionSpiritsFloor : LVDBase + { + [ReadOnly(true), Category("Version")] + public byte Version { get; internal set; } = 2; + + [Category("Line")] + public uint LineIndex { get; set; } + + [Category("Line")] + public string LineGroup { get; set; } + + [Category("Values")] + public float Unknown1 { get; set; } = 1.0f; + + [Category("Values")] + public float Unknown2 { get; set; } = 1.0f; + + [Category("Values")] + public float Unknown3 { get; set; } = 1.0f; + + [Category("Values")] + public float Unknown4 { get; set; } = 1.0f; + + [Category("Values")] + public float Unknown5 { get; set; } = 0.0f; + + [Category("Values")] + public float Unknown6 { get; set; } = 0.0f; + + public override void Read(BinaryReaderExt reader) + { + Version = reader.ReadByte(); + + base.Read(reader); + + LineIndex = reader.ReadUInt32(); + + reader.Skip(1); + LineGroup = reader.ReadString(); + reader.Skip(0x40 - (uint)LineGroup.Length - 1); + + if (Version < 2) + { + return; + } + + Unknown1 = reader.ReadSingle(); + Unknown2 = reader.ReadSingle(); + Unknown3 = reader.ReadSingle(); + Unknown4 = reader.ReadSingle(); + Unknown5 = reader.ReadSingle(); + Unknown6 = reader.ReadSingle(); + } + + public override void Write(BinaryWriterExt writer) + { + writer.Write(Version); + + base.Write(writer); + + writer.Write(LineIndex); + + writer.Write((byte)1); + writer.Write(LineGroup); + writer.Write(new byte[0x40 - LineGroup.Length - 1]); + + if (Version < 2) + { + return; + } + + writer.Write(Unknown1); + writer.Write(Unknown2); + writer.Write(Unknown3); + writer.Write(Unknown4); + writer.Write(Unknown5); + writer.Write(Unknown6); + } + } +} diff --git a/StudioSB/Scenes/LVD/LVDDamageShape.cs b/StudioSB/Scenes/LVD/LVDDamageShape.cs index a88728a..44da912 100644 --- a/StudioSB/Scenes/LVD/LVDDamageShape.cs +++ b/StudioSB/Scenes/LVD/LVDDamageShape.cs @@ -1,86 +1,42 @@ -using System; -using StudioSB.Tools; +using StudioSB.Tools; +using System.ComponentModel; namespace StudioSB.Scenes.LVD { - public enum LVDDamageShapeType + public class LVDDamageShape : LVDBase { - Sphere = 2, - Capsule = 3 - } + [ReadOnly(true), Category("Version")] + public byte Version { get; internal set; } = 1; - public class LVDDamageShape : LVDEntry - { - public LVDDamageShapeType Type { get; set; } + [Category("Shape"), TypeConverter(typeof(ExpandableObjectConverter))] + public LVDShape3 Shape { get; set; } = new LVDShape3(); + + public bool IsDamager { get; set; } - public float X { get; set; } - public float Y { get; set; } - public float Z { get; set; } - public float Dx { get; set; } - public float Dy { get; set; } - public float Dz { get; set; } - public float Radius { get; set; } - public byte Unknown1 { get; set; } - public int Unknown2 { get; set; } + public uint ID { get; set; } - public override void Read(BinaryReaderExt r) + public override void Read(BinaryReaderExt reader) { - base.Read(r); + Version = reader.ReadByte(); - r.Skip(1); - Type = (LVDDamageShapeType)r.ReadInt32(); - if (!Enum.IsDefined(typeof(LVDDamageShapeType), Type)) - throw new NotImplementedException($"Unknown damage shape type {Type} at offset {r.BaseStream.Position - 4}"); + base.Read(reader); - X = r.ReadSingle(); - Y = r.ReadSingle(); - Z = r.ReadSingle(); - if (Type == LVDDamageShapeType.Sphere) - { - Radius = r.ReadSingle(); - Dx = r.ReadSingle(); - Dy = r.ReadSingle(); - Dz = r.ReadSingle(); - } - if (Type == LVDDamageShapeType.Capsule) - { - Dx = r.ReadSingle(); - Dy = r.ReadSingle(); - Dz = r.ReadSingle(); - Radius = r.ReadSingle(); - } - Unknown1 = r.ReadByte(); - Unknown2 = r.ReadInt32(); + Shape.Read(reader); + + IsDamager = reader.ReadBoolean(); + ID = reader.ReadUInt32(); } public override void Write(BinaryWriterExt writer) { - base.Write(writer); + writer.Write(Version); - writer.Write((byte)1); - writer.Write((int)Type); + base.Write(writer); - writer.Write(X); - writer.Write(Y); - writer.Write(Z); - - if (Type == LVDDamageShapeType.Sphere) - { - writer.Write(Radius); - writer.Write(Dx); - writer.Write(Dy); - writer.Write(Dz); - } - if (Type == LVDDamageShapeType.Capsule) - { - writer.Write(Dx); - writer.Write(Dy); - writer.Write(Dz); - writer.Write(Radius); - } + Shape.Write(writer); - writer.Write(Unknown1); - writer.Write(Unknown2); + writer.Write(IsDamager); + writer.Write(ID); } } } diff --git a/StudioSB/Scenes/LVD/LVDEnemyGenerator.cs b/StudioSB/Scenes/LVD/LVDEnemyGenerator.cs index f701633..7dbd969 100644 --- a/StudioSB/Scenes/LVD/LVDEnemyGenerator.cs +++ b/StudioSB/Scenes/LVD/LVDEnemyGenerator.cs @@ -1,77 +1,116 @@ -using System; +using StudioSB.Tools; using System.Collections.Generic; -using StudioSB.Tools; +using System.ComponentModel; namespace StudioSB.Scenes.LVD { - public class LVDEnemyGenerator : LVDEntry + public class LVDEnemyGenerator : LVDBase { - public List Spawns { get; set; } = new List(); - public List Zones { get; set; } = new List(); - public int Unknown1 { get; set; } = 0; - public int ID { get; set; } - public List SpawnIDs { get; set; } = new List(); - public int Unknown2 { get; set; } = 0; - public List ZoneIDs { get; set; } = new List(); - - public override void Read(BinaryReaderExt r) + [ReadOnly(true), Category("Version")] + public byte Version { get; internal set; } = 3; + + public List Unknown1 { get; set; } = new List(); + + public List Unknown2 { get; set; } = new List(); + + public List Unknown3 { get; set; } = new List(); + + [Category("ID")] + public int Tag { get; set; } + + public List Unknown4 { get; set; } = new List(); + + public List Unknown5 { get; set; } = new List(); + + public List Unknown6 { get; set; } = new List(); + + public override void Read(BinaryReaderExt reader) { - base.Read(r); + Version = reader.ReadByte(); - r.Skip(0x2); //x01 01 - int spawnCount = r.ReadInt32(); - for (int i = 0; i < spawnCount; i++) + base.Read(reader); + + reader.Skip(1); + reader.Skip(1); + var unknown1Count = reader.ReadUInt32(); + for (uint i = 0; i < unknown1Count; i++) { - r.Skip(1); - var shape = new LVDShape(); - shape.Read(r); - Spawns.Add(shape); + reader.Skip(1); + var shape = new LVDShape2(); + shape.Read(reader); + Unknown1.Add(shape); } - r.Skip(0x2); //x01 01 - int zoneCount = r.ReadInt32(); - for (int i = 0; i < zoneCount; i++) + reader.Skip(1); + reader.Skip(1); + var unknown2Count = reader.ReadUInt32(); + for (uint i = 0; i < unknown2Count; i++) { - r.Skip(1); - var shape = new LVDShape(); - shape.Read(r); - Zones.Add(shape); + reader.Skip(1); + var shape = new LVDShape2(); + shape.Read(reader); + Unknown2.Add(shape); } - r.Skip(0x2); //x01 01 - Unknown1 = r.ReadInt32() ; //Only seen as 0 + reader.Skip(1); + reader.Skip(1); + var unknown3Count = reader.ReadUInt32(); + for (uint i = 0; i < unknown3Count; i++) + { + reader.Skip(1); + var shape = new LVDShape2(); + shape.Read(reader); + Unknown3.Add(shape); + } - r.Skip(1); //x01 - ID = r.ReadInt32(); + reader.Skip(1); + Tag = reader.ReadInt32(); - r.Skip(1); //x01 - int spawnIdCount = r.ReadInt32(); - for (int i = 0; i < spawnIdCount; i++) + if (Version < 2) { - r.Skip(1); - SpawnIDs.Add(r.ReadInt32()); + return; } - r.Skip(1); //x01 - Unknown2 = r.ReadInt32(); //Only seen as 0 + reader.Skip(1); + var unknown4Count = reader.ReadUInt32(); + for (int i = 0; i < unknown4Count; i++) + { + reader.Skip(1); + Unknown4.Add(reader.ReadInt32()); + } + + reader.Skip(1); + var unknown5Count = reader.ReadUInt32(); + for (int i = 0; i < unknown5Count; i++) + { + reader.Skip(1); + Unknown5.Add(reader.ReadInt32()); + } + + if (Version < 3) + { + return; + } - r.Skip(1); //x01 - int zoneIdCount = r.ReadInt32(); - for (int i = 0; i < zoneIdCount; i++) + reader.Skip(1); + var unknown6Count = reader.ReadUInt32(); + for (int i = 0; i < unknown6Count; i++) { - r.Skip(1); - ZoneIDs.Add(r.ReadInt32()); + reader.Skip(1); + Unknown6.Add(reader.ReadInt32()); } } public override void Write(BinaryWriterExt writer) { + writer.Write(Version); + base.Write(writer); writer.Write((byte)1); writer.Write((byte)1); - writer.Write(Spawns.Count); - foreach (var v in Spawns) + writer.Write(Unknown1.Count); + foreach (var v in Unknown1) { writer.Write((byte)1); v.Write(writer); @@ -79,8 +118,8 @@ public override void Write(BinaryWriterExt writer) writer.Write((byte)1); writer.Write((byte)1); - writer.Write(Zones.Count); - foreach (var v in Zones) + writer.Write(Unknown2.Count); + foreach (var v in Unknown2) { writer.Write((byte)1); v.Write(writer); @@ -88,25 +127,45 @@ public override void Write(BinaryWriterExt writer) writer.Write((byte)1); writer.Write((byte)1); - writer.Write(0); - + writer.Write(Unknown3.Count); + foreach (var v in Unknown3) + { + writer.Write((byte)1); + v.Write(writer); + } + writer.Write((byte)1); - writer.Write(ID); - + writer.Write(Tag); + + if (Version < 2) + { + return; + } + writer.Write((byte)1); - writer.Write(SpawnIDs.Count); - foreach (var v in SpawnIDs) + writer.Write(Unknown4.Count); + foreach (var v in Unknown4) { writer.Write((byte)1); writer.Write(v); } writer.Write((byte)1); - writer.Write(0); - + writer.Write(Unknown5.Count); + foreach (var v in Unknown5) + { + writer.Write((byte)1); + writer.Write(v); + } + + if (Version < 3) + { + return; + } + writer.Write((byte)1); - writer.Write(ZoneIDs.Count); - foreach (var v in ZoneIDs) + writer.Write(Unknown6.Count); + foreach (var v in Unknown6) { writer.Write((byte)1); writer.Write(v); diff --git a/StudioSB/Scenes/LVD/LVDEntry.cs b/StudioSB/Scenes/LVD/LVDEntry.cs deleted file mode 100644 index 83b5f0f..0000000 --- a/StudioSB/Scenes/LVD/LVDEntry.cs +++ /dev/null @@ -1,100 +0,0 @@ -using OpenTK; -using StudioSB.Tools; -using System.ComponentModel; - -namespace StudioSB.Scenes.LVD -{ - public class LVDEntry - { - [ReadOnly(true), Category("Entry")] - public long EntryFlags { get; internal set; } - - [ReadOnly(true), Category("Entry")] - public int EntryNumber { get; internal set; } - - [Category("Entry")] - public string EntryName { get; set; } - - [Category("Entry")] - public string EntryLabel { get; set; } - - [Category("Entry")] - public LVDVector3 StartPosition { get; set; } = new LVDVector3(0, 0, 0); - - [Category("Entry")] - public bool UseStartPosition { get; set; } = false; - - [Category("Entry")] - public LVDVector3 UnknownVector { get; set; } = new LVDVector3(0, 0, 0); - - [Category("Entry")] - public int UnknownIndex { get; set; } = 0; - - [Category("Entry")] - public int UnknownIndex2 { get; set; } = 0; // usually 0; related to connecting to bones? wily has 1 and 2 - - [Category("Entry")] - public string BoneName { get; set; } - - public virtual void Read(BinaryReaderExt r) - { - EntryFlags = r.ReadInt64(); - EntryNumber = r.ReadInt32(); - - bool hasString = r.ReadBoolean(); - EntryName = r.ReadString(0x38); - - bool hasLabel = r.ReadBoolean(); - EntryLabel = r.ReadString(0x40); - - bool hasStartPosition = r.ReadBoolean(); - StartPosition = new LVDVector3(r.ReadSingle(), r.ReadSingle(), r.ReadSingle()); - UseStartPosition = r.ReadBoolean(); - - // Unknown - r.Skip(1); - UnknownIndex2 = r.ReadInt32(); - - r.Skip(1); - UnknownVector = new LVDVector3(r.ReadSingle(), r.ReadSingle(), r.ReadSingle()); - UnknownIndex = r.ReadInt32(); - - r.Skip(1); - BoneName = r.ReadString(0x40); - } - - public virtual void Write(BinaryWriterExt writer) - { - writer.Write(EntryFlags); - writer.Write(EntryNumber); - - writer.Write((byte)1); - writer.Write(EntryName); - writer.Write(new byte[0x38 - EntryName.Length - 1]); - - writer.Write((byte)1); - writer.Write(EntryLabel); - writer.Write(new byte[0x40 - EntryLabel.Length - 1]); - - writer.Write((byte)1); - writer.Write(StartPosition.X); - writer.Write(StartPosition.Y); - writer.Write(StartPosition.Z); - writer.Write(UseStartPosition); - - writer.Write((byte)1); - writer.Write(UnknownIndex2); - - writer.Write((byte)1); - writer.Write(UnknownVector.X); - writer.Write(UnknownVector.Y); - writer.Write(UnknownVector.Z); - writer.Write(UnknownIndex); - - writer.Write((byte)1); - writer.Write(BoneName); - writer.Write(new byte[0x40 - BoneName.Length - 1]); - - } - } -} diff --git a/StudioSB/Scenes/LVD/LVDGeneralPoint.cs b/StudioSB/Scenes/LVD/LVDGeneralPoint.cs deleted file mode 100644 index d600dd1..0000000 --- a/StudioSB/Scenes/LVD/LVDGeneralPoint.cs +++ /dev/null @@ -1,45 +0,0 @@ -using StudioSB.Tools; - -namespace StudioSB.Scenes.LVD -{ - public class LVDGeneralPoint : LVDEntry - { - public int ID { get; set; } - public int Type { get; set; } = 4; - public float X { get; set; } - public float Y { get; set; } - public float Z { get; set; } - - public override void Read(BinaryReaderExt r) - { - base.Read(r); - - r.Skip(1); - ID = r.ReadInt32(); - - r.Skip(1); - Type = r.ReadInt32(); - - X = r.ReadSingle(); - Y = r.ReadSingle(); - Z = r.ReadSingle(); - r.Skip(0x10); - } - - public override void Write(BinaryWriterExt writer) - { - base.Write(writer); - - writer.Write((byte)1); - writer.Write(ID); - - writer.Write((byte)1); - writer.Write(Type); - - writer.Write(X); - writer.Write(Y); - writer.Write(Z); - writer.Write(new byte[0x10]); - } - } -} diff --git a/StudioSB/Scenes/LVD/LVDGeneralShape.cs b/StudioSB/Scenes/LVD/LVDGeneralShape.cs deleted file mode 100644 index 8e26d9a..0000000 --- a/StudioSB/Scenes/LVD/LVDGeneralShape.cs +++ /dev/null @@ -1,31 +0,0 @@ -using StudioSB.Tools; - -namespace StudioSB.Scenes.LVD -{ - public class LVDGeneralShape : LVDEntry - { - public int ID { get; set; } - public LVDShape Shape { get; set; } - - public override void Read(BinaryReaderExt r) - { - base.Read(r); - - r.Skip(1); - ID = r.ReadInt32(); - - Shape = new LVDShape(); - Shape.Read(r); - } - - public override void Write(BinaryWriterExt writer) - { - base.Write(writer); - - writer.Write((byte)1); - writer.Write(ID); - - Shape.Write(writer); - } - } -} diff --git a/StudioSB/Scenes/LVD/LVDGeneralShape2.cs b/StudioSB/Scenes/LVD/LVDGeneralShape2.cs new file mode 100644 index 0000000..be65c5e --- /dev/null +++ b/StudioSB/Scenes/LVD/LVDGeneralShape2.cs @@ -0,0 +1,42 @@ +using StudioSB.Tools; +using System.ComponentModel; + +namespace StudioSB.Scenes.LVD +{ + public class LVDGeneralShape2 : LVDBase + { + [ReadOnly(true), Category("Version")] + public byte Version { get; internal set; } = 1; + + [Category("ID")] + public int Tag { get; set; } + + [Category("Shape"), TypeConverter(typeof(ExpandableObjectConverter))] + public LVDShape2 Shape { get; set; } + + public override void Read(BinaryReaderExt reader) + { + Version = reader.ReadByte(); + + base.Read(reader); + + reader.Skip(1); + Tag = reader.ReadInt32(); + + Shape = new LVDShape2(); + Shape.Read(reader); + } + + public override void Write(BinaryWriterExt writer) + { + writer.Write(Version); + + base.Write(writer); + + writer.Write((byte)1); + writer.Write(Tag); + + Shape.Write(writer); + } + } +} diff --git a/StudioSB/Scenes/LVD/LVDGeneralShape3.cs b/StudioSB/Scenes/LVD/LVDGeneralShape3.cs new file mode 100644 index 0000000..392f3aa --- /dev/null +++ b/StudioSB/Scenes/LVD/LVDGeneralShape3.cs @@ -0,0 +1,42 @@ +using StudioSB.Tools; +using System.ComponentModel; + +namespace StudioSB.Scenes.LVD +{ + public class LVDGeneralShape3 : LVDBase + { + [ReadOnly(true), Category("Version")] + public byte Version { get; internal set; } = 1; + + [Category("ID")] + public int Tag { get; set; } + + [Category("Shape"), TypeConverter(typeof(ExpandableObjectConverter))] + public LVDShape3 Shape { get; set; } + + public override void Read(BinaryReaderExt reader) + { + Version = reader.ReadByte(); + + base.Read(reader); + + reader.Skip(1); + Tag = reader.ReadInt32(); + + Shape = new LVDShape3(); + Shape.Read(reader); + } + + public override void Write(BinaryWriterExt writer) + { + writer.Write(Version); + + base.Write(writer); + + writer.Write((byte)1); + writer.Write(Tag); + + Shape.Write(writer); + } + } +} diff --git a/StudioSB/Scenes/LVD/LVDGeneralVector.cs b/StudioSB/Scenes/LVD/LVDGeneralVector.cs deleted file mode 100644 index 47f750c..0000000 --- a/StudioSB/Scenes/LVD/LVDGeneralVector.cs +++ /dev/null @@ -1,33 +0,0 @@ -using StudioSB.Tools; - -namespace StudioSB.Scenes.LVD -{ - public class LVDGeneralVector : LVDEntry - { - public float X { get; set; } - public float Y { get; set; } - public float Z { get; set; } - - public override void Read(BinaryReaderExt r) - { - base.Read(r); - - r.ReadByte(); - - X = r.ReadSingle(); - Y = r.ReadSingle(); - Z = r.ReadSingle(); - } - - public override void Write(BinaryWriterExt writer) - { - base.Write(writer); - - writer.Write((byte)1); - - writer.Write(X); - writer.Write(Y); - writer.Write(Z); - } - } -} diff --git a/StudioSB/Scenes/LVD/LVDItemPopupRegion.cs b/StudioSB/Scenes/LVD/LVDItemPopupRegion.cs new file mode 100644 index 0000000..b0bb35f --- /dev/null +++ b/StudioSB/Scenes/LVD/LVDItemPopupRegion.cs @@ -0,0 +1,58 @@ +using StudioSB.Tools; +using System.Collections.Generic; +using System.ComponentModel; + +namespace StudioSB.Scenes.LVD +{ + public class LVDItemPopupRegion : LVDBase + { + [ReadOnly(true), Category("Version")] + public byte Version { get; internal set; } = 1; + + [Category("ID")] + public int Tag { get; set; } + + [Category("Regions")] + public List Regions { get; set; } = new List(); + + public override void Read(BinaryReaderExt reader) + { + Version = reader.ReadByte(); + + base.Read(reader); + + reader.Skip(1); + Tag = reader.ReadInt32(); + + reader.Skip(1); + reader.Skip(1); + uint regionCount = reader.ReadUInt32(); + for (uint i = 0; i < regionCount; i++) + { + reader.Skip(1); + var region = new LVDShape2(); + region.Read(reader); + Regions.Add(region); + } + } + + public override void Write(BinaryWriterExt writer) + { + writer.Write(Version); + + base.Write(writer); + + writer.Write((byte)1); + writer.Write(Tag); + + writer.Write((byte)1); + writer.Write((byte)1); + writer.Write(Regions.Count); + foreach (var v in Regions) + { + writer.Write((byte)1); + v.Write(writer); + } + } + } +} diff --git a/StudioSB/Scenes/LVD/LVDItemSpawner.cs b/StudioSB/Scenes/LVD/LVDItemSpawner.cs deleted file mode 100644 index c802d5d..0000000 --- a/StudioSB/Scenes/LVD/LVDItemSpawner.cs +++ /dev/null @@ -1,48 +0,0 @@ -using System.Collections.Generic; -using StudioSB.Tools; - -namespace StudioSB.Scenes.LVD -{ - public class LVDItemSpawner : LVDEntry - { - public int ID { get; internal set; } = 0x09840001; - public List Sections { get; set; } = new List(); - - public override void Read(BinaryReaderExt r) - { - base.Read(r); - - r.Skip(1); - ID = r.ReadInt32(); - - r.Skip(1); - r.Skip(1); - int sectionCount = r.ReadInt32(); - for (int i = 0; i < sectionCount; i++) - { - r.Skip(1); - var shape = new LVDShape(); - shape.Read(r); - Sections.Add(shape); - } - } - - public override void Write(BinaryWriterExt writer) - { - base.Write(writer); - - writer.Write((byte)1); - writer.Write(ID); - - writer.Write((byte)1); - writer.Write((byte)1); - - writer.Write(Sections.Count); - foreach(var v in Sections) - { - writer.Write((byte)1); - v.Write(writer); - } - } - } -} diff --git a/StudioSB/Scenes/LVD/LVDPTrainerFloatingFloor.cs b/StudioSB/Scenes/LVD/LVDPTrainerFloatingFloor.cs new file mode 100644 index 0000000..ce29266 --- /dev/null +++ b/StudioSB/Scenes/LVD/LVDPTrainerFloatingFloor.cs @@ -0,0 +1,32 @@ +using StudioSB.Tools; +using System.ComponentModel; + +namespace StudioSB.Scenes.LVD +{ + public class LVDPTrainerFloatingFloor : LVDBase + { + [ReadOnly(true), Category("Version")] + public byte Version { get; internal set; } = 1; + + [Category("Position"), TypeConverter(typeof(ExpandableObjectConverter))] + public LVDVector3 Position { get; set; } = new LVDVector3(0.0f, 0.0f, 0.0f); + + public override void Read(BinaryReaderExt reader) + { + Version = reader.ReadByte(); + + base.Read(reader); + + Position.Read(reader); + } + + public override void Write(BinaryWriterExt writer) + { + writer.Write(Version); + + base.Write(writer); + + Position.Write(writer); + } + } +} diff --git a/StudioSB/Scenes/LVD/LVDPTrainerRange.cs b/StudioSB/Scenes/LVD/LVDPTrainerRange.cs new file mode 100644 index 0000000..073a065 --- /dev/null +++ b/StudioSB/Scenes/LVD/LVDPTrainerRange.cs @@ -0,0 +1,88 @@ +using StudioSB.Tools; +using System.Collections.Generic; +using System.ComponentModel; + +namespace StudioSB.Scenes.LVD +{ + public class LVDPTrainerRange : LVDBase + { + [ReadOnly(true), Category("Version")] + public byte Version { get; internal set; } = 4; + + [Category("Range"), TypeConverter(typeof(ExpandableObjectConverter))] + public LVDVector3 BoundaryMin { get; set; } = new LVDVector3(0.0f, 0.0f, 0.0f); + + [Category("Range"), TypeConverter(typeof(ExpandableObjectConverter))] + public LVDVector3 BoundaryMax { get; set; } = new LVDVector3(0.0f, 0.0f, 0.0f); + + [Category("Range")] + public List Trainers { get; set; } = new List(); + + [Category("Parent")] + public string ParentModelName { get; set; } + + [Category("Parent")] + public string ParentJointName { get; set; } + + public override void Read(BinaryReaderExt reader) + { + Version = reader.ReadByte(); + + base.Read(reader); + + BoundaryMin.Read(reader); + + BoundaryMax.Read(reader); + + reader.Skip(1); + uint trainerCount = reader.ReadUInt32(); + for (uint i = 0; i < trainerCount; i++) + { + LVDVector3 trainer = new LVDVector3(0.0f, 0.0f, 0.0f); + + trainer.Read(reader); + Trainers.Add(trainer); + } + + if (Version > 1) + { + reader.Skip(1); + ParentModelName = reader.ReadString(); + reader.Skip(0x40 - (uint)ParentModelName.Length - 1); + + reader.Skip(1); + ParentJointName = reader.ReadString(); + reader.Skip(0x40 - (uint)ParentJointName.Length - 1); + } + } + + public override void Write(BinaryWriterExt writer) + { + writer.Write(Version); + + base.Write(writer); + + BoundaryMin.Write(writer); + + BoundaryMax.Write(writer); + + writer.Write((byte)1); + writer.Write(Trainers.Count); + foreach (var v in Trainers) + { + v.Write(writer); + } + + if (Version > 1) + { + writer.Write((byte)1); + writer.Write(ParentModelName); + writer.Write(new byte[0x40 - ParentModelName.Length - 1]); + + writer.Write((byte)1); + writer.Write(ParentJointName); + writer.Write(new byte[0x40 - ParentJointName.Length - 1]); + } + } + } +} diff --git a/StudioSB/Scenes/LVD/LVDPoint.cs b/StudioSB/Scenes/LVD/LVDPoint.cs new file mode 100644 index 0000000..5287c96 --- /dev/null +++ b/StudioSB/Scenes/LVD/LVDPoint.cs @@ -0,0 +1,46 @@ +using StudioSB.Tools; +using System.ComponentModel; + +namespace StudioSB.Scenes.LVD +{ + public class LVDPoint : LVDBase + { + [ReadOnly(true), Category("Version")] + public byte Version { get; internal set; } = 2; + + [Category("Position"), TypeConverter(typeof(ExpandableObjectConverter))] + public LVDVector2 Position { get; set; } = new LVDVector2(0.0f, 0.0f); + + public override void Read(BinaryReaderExt reader) + { + Version = reader.ReadByte(); + + if (Version < 2) + { + MetaInfo.Read(reader); + } + else + { + base.Read(reader); + } + + Position.Read(reader); + } + + public override void Write(BinaryWriterExt writer) + { + writer.Write(Version); + + if (Version < 2) + { + MetaInfo.Write(writer); + } + else + { + base.Write(writer); + } + + Position.Write(writer); + } + } +} diff --git a/StudioSB/Scenes/LVD/LVDRangeCurve.cs b/StudioSB/Scenes/LVD/LVDRangeCurve.cs deleted file mode 100644 index 8e5936b..0000000 --- a/StudioSB/Scenes/LVD/LVDRangeCurve.cs +++ /dev/null @@ -1,81 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using StudioSB.Tools; - -namespace StudioSB.Scenes.LVD -{ - public class LVDRangeCurve : LVDEntry - { - public LVDVector3 Vector1 { get; set; } - public LVDVector3 Vector2 { get; set; } - - public List Vectors { get; set; } = new List(); - - public float[] Mat4x4_1 { get; set; } = new float[16]; - - public float[] Mat4x4_2 { get; set; } = new float[16]; - - public override void Read(BinaryReaderExt r) - { - base.Read(r); - r.ReadByte(); - Vector1 = new LVDVector3(r.ReadSingle(), r.ReadSingle(), r.ReadSingle()); - r.ReadByte(); - Vector2 = new LVDVector3(r.ReadSingle(), r.ReadSingle(), r.ReadSingle()); - r.ReadByte(); - - int vec3Count = r.ReadInt32(); - for(int i = 0; i < vec3Count; i++) - { - r.ReadByte(); - Vectors.Add(new LVDVector3(r.ReadSingle(), r.ReadSingle(), r.ReadSingle())); - } - - r.ReadByte(); - Mat4x4_1 = new float[16]; - for (int i = 0; i < 16; i++) - Mat4x4_1[i] = r.ReadSingle(); - - r.ReadByte(); - Mat4x4_2 = new float[16]; - for (int i = 0; i < 16; i++) - Mat4x4_2[i] = r.ReadSingle(); - } - - public override void Write(BinaryWriterExt writer) - { - base.Write(writer); - - writer.Write((byte)1); - writer.Write(Vector1.X); - writer.Write(Vector1.Y); - writer.Write(Vector1.Z); - - writer.Write((byte)1); - writer.Write(Vector2.X); - writer.Write(Vector2.Y); - writer.Write(Vector2.Z); - - writer.Write((byte)1); - writer.Write(Vectors.Count); - foreach(var v in Vectors) - { - writer.Write((byte)1); - writer.Write(v.X); - writer.Write(v.Y); - writer.Write(v.Z); - } - - writer.Write((byte)1); - foreach (var v in Mat4x4_1) - writer.Write(v); - - writer.Write((byte)1); - foreach (var v in Mat4x4_2) - writer.Write(v); - } - } -} diff --git a/StudioSB/Scenes/LVD/LVDRect.cs b/StudioSB/Scenes/LVD/LVDRect.cs new file mode 100644 index 0000000..35902dd --- /dev/null +++ b/StudioSB/Scenes/LVD/LVDRect.cs @@ -0,0 +1,45 @@ +using StudioSB.Tools; +using System.ComponentModel; + +namespace StudioSB.Scenes.LVD +{ + public class LVDRect + { + [ReadOnly(true), Category("Version")] + public byte Version { get; internal set; } = 1; + + [Category("Rectangle")] + public float Left { get; set; } + + [Category("Rectangle")] + public float Right { get; set; } + + [Category("Rectangle")] + public float Top { get; set; } + + [Category("Rectangle")] + public float Bottom { get; set; } + + public override string ToString() + { + return $"({Left}, {Right}, {Top}, {Bottom})"; + } + public void Read(BinaryReaderExt reader) + { + Version = reader.ReadByte(); + Left = reader.ReadSingle(); + Right = reader.ReadSingle(); + Top = reader.ReadSingle(); + Bottom = reader.ReadSingle(); + } + + public void Write(BinaryWriterExt writer) + { + writer.Write(Version); + writer.Write(Left); + writer.Write(Right); + writer.Write(Top); + writer.Write(Bottom); + } + } +} diff --git a/StudioSB/Scenes/LVD/LVDRegion.cs b/StudioSB/Scenes/LVD/LVDRegion.cs new file mode 100644 index 0000000..4fe08b9 --- /dev/null +++ b/StudioSB/Scenes/LVD/LVDRegion.cs @@ -0,0 +1,46 @@ +using StudioSB.Tools; +using System.ComponentModel; + +namespace StudioSB.Scenes.LVD +{ + public class LVDRegion : LVDBase + { + [ReadOnly(true), Category("Version")] + public byte Version { get; internal set; } = 2; + + [Category("Rectangle"), TypeConverter(typeof(ExpandableObjectConverter))] + public LVDRect Rectangle { get; set; } = new LVDRect(); + + public override void Read(BinaryReaderExt reader) + { + Version = reader.ReadByte(); + + if (Version < 2) + { + MetaInfo.Read(reader); + } + else + { + base.Read(reader); + } + + Rectangle.Read(reader); + } + + public override void Write(BinaryWriterExt writer) + { + writer.Write(Version); + + if (Version < 2) + { + MetaInfo.Write(writer); + } + else + { + base.Write(writer); + } + + Rectangle.Write(writer); + } + } +} diff --git a/StudioSB/Scenes/LVD/LVDShape.cs b/StudioSB/Scenes/LVD/LVDShape.cs deleted file mode 100644 index 5ca9bf1..0000000 --- a/StudioSB/Scenes/LVD/LVDShape.cs +++ /dev/null @@ -1,68 +0,0 @@ -using StudioSB.Tools; -using System.Collections.Generic; - -namespace StudioSB.Scenes.LVD -{ - public enum LVDShapeType : int - { - Point = 1, - Circle = 2, - Rectangle = 3, - Path = 4 - } - - public class LVDShape - { - public LVDShapeType Type { get; set; } - public float X { get; set; } - public float Y { get; set; } - public float Z { get; set; } - public float W { get; set; } - public List Points { get; set; } = new List(); - - public override string ToString() - { - return Type.ToString(); - } - - public void Read(BinaryReaderExt r) - { - r.ReadByte(); - Type = (LVDShapeType)r.ReadInt32(); - X = r.ReadSingle(); - Y = r.ReadSingle(); - Z = r.ReadSingle(); - W = r.ReadSingle(); - - r.ReadByte(); - - r.ReadByte(); - int pointCount = r.ReadInt32(); - for (int i = 0; i < pointCount; i++) - { - r.Skip(1); - Points.Add(new LVDVector2(r.ReadSingle(), r.ReadSingle())); - } - } - - public void Write(BinaryWriterExt writer) - { - writer.Write((byte)3); - writer.Write((int)Type); - writer.Write(X); - writer.Write(Y); - writer.Write(Z); - writer.Write(W); - - writer.Write((byte)1); - writer.Write((byte)1); - writer.Write(Points.Count); - foreach(var v in Points) - { - writer.Write((byte)1); - writer.Write(v.X); - writer.Write(v.Y); - } - } - } -} diff --git a/StudioSB/Scenes/LVD/LVDShape2.cs b/StudioSB/Scenes/LVD/LVDShape2.cs new file mode 100644 index 0000000..7f29d45 --- /dev/null +++ b/StudioSB/Scenes/LVD/LVDShape2.cs @@ -0,0 +1,82 @@ +using StudioSB.Tools; +using System.Collections.Generic; +using System.ComponentModel; + +namespace StudioSB.Scenes.LVD +{ + public enum LVDShape2Type : uint + { + Point = 1, + Circle = 2, + Rectangle = 3, + Path = 4 + } + + public class LVDShape2 + { + [ReadOnly(true), Category("Version")] + public byte Version { get; internal set; } = 3; + + [Category("Type")] + public LVDShape2Type Type { get; set; } + + [Category("Values")] + public float X { get; set; } + + [Category("Values")] + public float Y { get; set; } + + [Category("Values")] + public float Z { get; set; } + + [Category("Values")] + public float W { get; set; } + + [Category("Values (Path)")] + public List Points { get; set; } = new List(); + + public override string ToString() + { + return Type.ToString(); + } + + public void Read(BinaryReaderExt reader) + { + Version = reader.ReadByte(); + Type = (LVDShape2Type)reader.ReadUInt32(); + X = reader.ReadSingle(); + Y = reader.ReadSingle(); + Z = reader.ReadSingle(); + W = reader.ReadSingle(); + + reader.Skip(1); + reader.Skip(1); + uint pointCount = reader.ReadUInt32(); + for (uint i = 0; i < pointCount; i++) + { + LVDVector2 point = new LVDVector2(0.0f, 0.0f); + + point.Read(reader); + Points.Add(point); + } + } + + public void Write(BinaryWriterExt writer) + { + writer.Write(Version); + writer.Write((uint)Type); + writer.Write(X); + writer.Write(Y); + writer.Write(Z); + writer.Write(W); + + writer.Write((byte)1); + writer.Write((byte)1); + writer.Write(Points.Count); + foreach (var v in Points) + { + v.Write(writer); + } + } + } +} diff --git a/StudioSB/Scenes/LVD/LVDShape3.cs b/StudioSB/Scenes/LVD/LVDShape3.cs new file mode 100644 index 0000000..9dec0dc --- /dev/null +++ b/StudioSB/Scenes/LVD/LVDShape3.cs @@ -0,0 +1,74 @@ +using StudioSB.Tools; +using System.ComponentModel; + +namespace StudioSB.Scenes.LVD +{ + public enum LVDShape3Type : uint + { + Box = 1, + Sphere = 2, + Capsule = 3, + Point = 4 + } + + public class LVDShape3 + { + [ReadOnly(true), Category("Version")] + public byte Version { get; internal set; } = 1; + + [Category("Type")] + public LVDShape3Type Type { get; set; } + + [Category("Values")] + public float X { get; set; } + + [Category("Values")] + public float Y { get; set; } + + [Category("Values")] + public float Z { get; set; } + + [Category("Values")] + public float W { get; set; } + + [Category("Values")] + public float S { get; set; } + + [Category("Values")] + public float R { get; set; } + + [Category("Values")] + public float T { get; set; } + + public override string ToString() + { + return Type.ToString(); + } + + public void Read(BinaryReaderExt reader) + { + Version = reader.ReadByte(); + Type = (LVDShape3Type)reader.ReadUInt32(); + X = reader.ReadSingle(); + Y = reader.ReadSingle(); + Z = reader.ReadSingle(); + W = reader.ReadSingle(); + S = reader.ReadSingle(); + R = reader.ReadSingle(); + T = reader.ReadSingle(); + } + + public void Write(BinaryWriterExt writer) + { + writer.Write(Version); + writer.Write((uint)Type); + writer.Write(X); + writer.Write(Y); + writer.Write(Z); + writer.Write(W); + writer.Write(S); + writer.Write(R); + writer.Write(T); + } + } +} diff --git a/StudioSB/Scenes/LVD/LVDSpawn.cs b/StudioSB/Scenes/LVD/LVDSpawn.cs deleted file mode 100644 index 9bc01d4..0000000 --- a/StudioSB/Scenes/LVD/LVDSpawn.cs +++ /dev/null @@ -1,28 +0,0 @@ -using StudioSB.Tools; - -namespace StudioSB.Scenes.LVD -{ - public class LVDSpawn : LVDEntry - { - public float X { get; set; } = 0; - public float Y { get; set; } = 0; - - public override void Read(BinaryReaderExt r) - { - base.Read(r); - - r.ReadByte(); - X = r.ReadSingle(); - Y = r.ReadSingle(); - } - - public override void Write(BinaryWriterExt writer) - { - base.Write(writer); - - writer.Write((byte)1); - writer.Write(X); - writer.Write(Y); - } - } -} diff --git a/StudioSB/Scenes/LVD/LVDVector2.cs b/StudioSB/Scenes/LVD/LVDVector2.cs new file mode 100644 index 0000000..bb5fcee --- /dev/null +++ b/StudioSB/Scenes/LVD/LVDVector2.cs @@ -0,0 +1,58 @@ +using StudioSB.Tools; +using System; +using System.ComponentModel; + +namespace StudioSB.Scenes.LVD +{ + public class LVDVector2 + { + [ReadOnly(true), Category("Version")] + public byte Version { get; internal set; } = 1; + + [Category("Component")] + public float X { get; set; } + + [Category("Component")] + public float Y { get; set; } + + public LVDVector2(float x, float y) + { + X = x; + Y = y; + } + + public override string ToString() + { + return $"({X}, {Y})"; + } + + public LVDVector2 Normalized() + { + float length = (float)Math.Sqrt(X * X + Y * Y); + + return new LVDVector2(X / length, Y / length); + } + + public static LVDVector2 GenerateNormal(LVDVector2 v1, LVDVector2 v2) + { + LVDVector2 normal = new LVDVector2(v2.Y - v1.Y, v2.X - v1.X).Normalized(); + normal.X *= -1.0f; + + return normal; + } + + public void Read(BinaryReaderExt reader) + { + Version = reader.ReadByte(); + X = reader.ReadSingle(); + Y = reader.ReadSingle(); + } + + public void Write(BinaryWriterExt writer) + { + writer.Write(Version); + writer.Write(X); + writer.Write(Y); + } + } +} diff --git a/StudioSB/Scenes/LVD/LVDVector3.cs b/StudioSB/Scenes/LVD/LVDVector3.cs new file mode 100644 index 0000000..f7aa045 --- /dev/null +++ b/StudioSB/Scenes/LVD/LVDVector3.cs @@ -0,0 +1,48 @@ +using StudioSB.Tools; +using System.ComponentModel; + +namespace StudioSB.Scenes.LVD +{ + public class LVDVector3 + { + [ReadOnly(true), Category("Version")] + public byte Version { get; internal set; } = 1; + + [Category("Component")] + public float X { get; set; } + + [Category("Component")] + public float Y { get; set; } + + [Category("Component")] + public float Z { get; set; } + + public LVDVector3(float x, float y, float z) + { + X = x; + Y = y; + Z = z; + } + + public override string ToString() + { + return $"({X}, {Y}, {Z})"; + } + + public void Read(BinaryReaderExt reader) + { + Version = reader.ReadByte(); + X = reader.ReadSingle(); + Y = reader.ReadSingle(); + Z = reader.ReadSingle(); + } + + public void Write(BinaryWriterExt writer) + { + writer.Write(Version); + writer.Write(X); + writer.Write(Y); + writer.Write(Z); + } + } +} diff --git a/StudioSB/Scenes/LVD/LevelData.cs b/StudioSB/Scenes/LVD/LevelData.cs index 485fbf6..9dfd69e 100644 --- a/StudioSB/Scenes/LVD/LevelData.cs +++ b/StudioSB/Scenes/LVD/LevelData.cs @@ -9,371 +9,524 @@ namespace StudioSB.Scenes.LVD [Serializable] public class LevelData { - [ReadOnly(true)] - public int Heading { get; internal set; } = 0x01; + [ReadOnly(true), Category("Header")] + public uint Unknown { get; internal set; } = 1; - [ReadOnly(true)] - public byte VersionMinor { get; internal set; } = 0x0D; + [ReadOnly(true), Category("Header")] + public byte Version { get; internal set; } = 13; - [ReadOnly(true)] - public byte VersionMajor { get; internal set; } = 0x01; - - [ReadOnly(true)] - public string Magic { get; internal set; } = "LVD1"; + [ReadOnly(true), Category("Header")] + public string Signature { get; internal set; } = "LVD1"; public List Collisions = new List(); + public List StartPositions = new List(); + public List RestartPositions = new List(); + public List CameraRegions = new List(); + public List DeathRegions = new List(); + public List EnemyGenerators = new List(); + public List DamageShapes = new List(); + public List ItemPopupRegions = new List(); + public List PTrainerRanges = new List(); + public List PTrainerFloatingFloors = new List(); + public List GeneralShapes2D = new List(); + public List GeneralShapes3D = new List(); + public List ShrinkedCameraRegions = new List(); + public List ShrinkedDeathRegions = new List(); - public List Spawns = new List(); + public LevelData() + { + } - public List Respawns = new List(); + public LevelData(string FileName) + { + Open(FileName); + } - public List CameraBounds = new List(); + public void Open(string FileName) + { + using (BinaryReaderExt stream = new BinaryReaderExt(new FileStream(FileName, FileMode.Open))) + { + Read(stream); - public List BlastZoneBounds = new List(); + if (stream.BaseStream.Length != stream.BaseStream.Position) + { + stream.PrintPosition(); + throw new Exception("Error fully parsing LVD file " + stream.BaseStream.Position.ToString("X")); + } + } + } - public List EnemyGenerators = new List(); + public void Save(string FileName) + { + File.WriteAllBytes(FileName, GetData()); + } + + public byte[] GetData() + { + MemoryStream stream = new MemoryStream(); - public List ItemSpawners = new List(); + using (BinaryWriterExt writer = new BinaryWriterExt(stream)) + { + Write(writer); + } - public List DamageShapes = new List(); + byte[] output = stream.ToArray(); + stream.Close(); + stream.Dispose(); + return output; + } - public List GeneralPoints = new List(); + public void Read(BinaryReaderExt reader) + { + reader.BigEndian = true; - public List GeneralShapes = new List(); + Unknown = reader.ReadUInt32(); + Version = reader.ReadByte(); - // version > 10 ie Smash Ultimate + reader.ReadByte(); + Signature = new string(reader.ReadChars(Signature.Length)); - public List RangeCurves = new List(); + reader.ReadByte(); + uint collisionCount = reader.ReadUInt32(); + for (uint i = 0; i < collisionCount; i++) + { + LVDCollision collision = new LVDCollision(); - public List GeneralVectors = new List(); + collision.Read(reader); + Collisions.Add(collision); + } - public List ShrunkCameraBounds = new List(); + reader.ReadByte(); + uint startPositionCount = reader.ReadUInt32(); + for (uint i = 0; i < startPositionCount; i++) + { + LVDPoint startPosition = new LVDPoint(); - public List ShrunkBlastZoneBounds = new List(); + startPosition.Read(reader); + StartPositions.Add(startPosition); + } - public LevelData() - { - //TODO: make defaults? - } + reader.ReadByte(); + uint restartPositionCount = reader.ReadUInt32(); + for (uint i = 0; i < restartPositionCount; i++) + { + LVDPoint restartPosition = new LVDPoint(); - public LevelData(string FileName) - { - Open(FileName); - } + restartPosition.Read(reader); + RestartPositions.Add(restartPosition); + } - public void Open(string FileName) - { - using (BinaryReaderExt stream = new BinaryReaderExt(new FileStream(FileName, FileMode.Open))) + reader.ReadByte(); + uint cameraRegionCount = reader.ReadUInt32(); + for (uint i = 0; i < cameraRegionCount; i++) { - stream.BigEndian = true; + LVDRegion cameraRegion = new LVDRegion(); - Heading = stream.ReadInt32(); - VersionMinor = stream.ReadByte(); - VersionMajor = stream.ReadByte(); - Magic = new string(stream.ReadChars(4)); + cameraRegion.Read(reader); + CameraRegions.Add(cameraRegion); + } - stream.ReadByte(); - var collisionCount = stream.ReadInt32(); - for(int i = 0; i < collisionCount; i++) - { - LVDCollision col = new LVDCollision(); - col.Read(stream, VersionMinor); - Collisions.Add(col); - } + reader.ReadByte(); + uint deathRegionCount = reader.ReadUInt32(); + for (uint i = 0; i < deathRegionCount; i++) + { + LVDRegion deathRegion = new LVDRegion(); - stream.ReadByte(); - var spawnCount = stream.ReadInt32(); - for (int i = 0; i < spawnCount; i++) - { - LVDSpawn spawn = new LVDSpawn(); - spawn.Read(stream); - Spawns.Add(spawn); - } + deathRegion.Read(reader); + DeathRegions.Add(deathRegion); + } - stream.ReadByte(); - var respawnCount = stream.ReadInt32(); - for (int i = 0; i < respawnCount; i++) - { - LVDSpawn respawn = new LVDSpawn(); - respawn.Read(stream); - Respawns.Add(respawn); - } - - stream.ReadByte(); - var boundsCount = stream.ReadInt32(); - for (int i = 0; i < boundsCount; i++) - { - LVDBounds bound = new LVDBounds(); - bound.Read(stream); - CameraBounds.Add(bound); - } + reader.ReadByte(); + uint enemyGeneratorCount = reader.ReadUInt32(); + for (uint i = 0; i < enemyGeneratorCount; i++) + { + LVDEnemyGenerator enemyGenerator = new LVDEnemyGenerator(); - stream.ReadByte(); - var blastCount = stream.ReadInt32(); - for (int i = 0; i < blastCount; i++) - { - LVDBounds blast = new LVDBounds(); - blast.Read(stream); - BlastZoneBounds.Add(blast); - } - - stream.ReadByte(); - int enemyGenCount = stream.ReadInt32(); - for(int i = 0; i < enemyGenCount; i++) - { - LVDEnemyGenerator enGen = new LVDEnemyGenerator(); - enGen.Read(stream); - EnemyGenerators.Add(enGen); - } + enemyGenerator.Read(reader); + EnemyGenerators.Add(enemyGenerator); + } - stream.ReadByte(); - if (stream.ReadInt32() > 0) - throw new NotImplementedException("Unknown LVD Section at 0x" + stream.BaseStream.Position.ToString("X")); + if (Version < 2) + { + return; + } - stream.ReadByte(); - if (stream.ReadInt32() > 0) - throw new NotImplementedException("Unknown LVD Section at 0x" + stream.BaseStream.Position.ToString("X")); + reader.ReadByte(); + if (reader.ReadUInt32() > 0) + { + throw new NotImplementedException("Unknown LVD Section at 0x" + reader.BaseStream.Position.ToString("X")); + } - stream.ReadByte(); - if (stream.ReadInt32() > 0) - throw new NotImplementedException("Unknown LVD Section at 0x" + stream.BaseStream.Position.ToString("X")); + if (Version < 3) + { + return; + } - stream.ReadByte(); - if (stream.ReadInt32() > 0) - throw new NotImplementedException("Unknown LVD Section at 0x" + stream.BaseStream.Position.ToString("X")); + reader.ReadByte(); + if (reader.ReadUInt32() > 0) + { + throw new NotImplementedException("Unknown LVD Section at 0x" + reader.BaseStream.Position.ToString("X")); + } - stream.ReadByte(); - if (stream.ReadInt32() > 0) - throw new NotImplementedException("Unknown LVD Section at 0x" + stream.BaseStream.Position.ToString("X")); + reader.ReadByte(); + if (reader.ReadUInt32() > 0) + { + throw new NotImplementedException("Unknown LVD Section at 0x" + reader.BaseStream.Position.ToString("X")); + } - stream.ReadByte(); - int damageCount = stream.ReadInt32(); - for (int i = 0; i < damageCount; i++) - { - LVDDamageShape shape = new LVDDamageShape(); - shape.Read(stream); - DamageShapes.Add(shape); - } - - stream.ReadByte(); - int itemSpawnCount = stream.ReadInt32(); - for (int i = 0; i < itemSpawnCount; i++) - { - LVDItemSpawner spawn = new LVDItemSpawner(); - spawn.Read(stream); - ItemSpawners.Add(spawn); - } - - if (VersionMinor > 0xA) - { - stream.ReadByte(); - int genCurveCount = stream.ReadInt32(); - for (int i = 0; i < genCurveCount; i++) - { - LVDRangeCurve point = new LVDRangeCurve(); - point.Read(stream); - RangeCurves.Add(point); - } - - stream.ReadByte(); - int genCurveCount2 = stream.ReadInt32(); - for (int i = 0; i < genCurveCount2; i++) - { - LVDGeneralVector point = new LVDGeneralVector(); - point.Read(stream); - GeneralVectors.Add(point); - } - } - - stream.ReadByte(); - int genShapeCount = stream.ReadInt32(); - for (int i = 0; i < genShapeCount; i++) - { - LVDGeneralShape shape = new LVDGeneralShape(); - shape.Read(stream); - GeneralShapes.Add(shape); - } - - stream.ReadByte(); - int genPointCount = stream.ReadInt32(); - for (int i = 0; i < genPointCount; i++) + reader.ReadByte(); + if (reader.ReadUInt32() > 0) + { + throw new NotImplementedException("Unknown LVD Section at 0x" + reader.BaseStream.Position.ToString("X")); + } + + reader.ReadByte(); + if (reader.ReadUInt32() > 0) + { + throw new NotImplementedException("Unknown LVD Section at 0x" + reader.BaseStream.Position.ToString("X")); + } + + if (Version < 4) + { + return; + } + + reader.ReadByte(); + uint damageShapeCount = reader.ReadUInt32(); + for (uint i = 0; i < damageShapeCount; i++) + { + LVDDamageShape damageShape = new LVDDamageShape(); + + damageShape.Read(reader); + DamageShapes.Add(damageShape); + } + + if (Version < 5) + { + return; + } + + reader.ReadByte(); + uint itemPopupRegionCount = reader.ReadUInt32(); + for (uint i = 0; i < itemPopupRegionCount; i++) + { + LVDItemPopupRegion itemPopupRegion = new LVDItemPopupRegion(); + + itemPopupRegion.Read(reader); + ItemPopupRegions.Add(itemPopupRegion); + } + + if (Version > 11) + { + reader.ReadByte(); + uint ptrainerRangeCount = reader.ReadUInt32(); + for (uint i = 0; i < ptrainerRangeCount; i++) { - LVDGeneralPoint point = new LVDGeneralPoint(); - point.Read(stream); - GeneralPoints.Add(point); + LVDPTrainerRange ptrainerRange = new LVDPTrainerRange(); + + ptrainerRange.Read(reader); + PTrainerRanges.Add(ptrainerRange); } - - stream.ReadByte(); - if (stream.ReadInt32() > 0) - throw new NotImplementedException("Unknown LVD Section at 0x" + stream.BaseStream.Position.ToString("X")); - - stream.ReadByte(); - if (stream.ReadInt32() > 0) - throw new NotImplementedException("Unknown LVD Section at 0x" + stream.BaseStream.Position.ToString("X")); - - stream.ReadByte(); - if (stream.ReadInt32() > 0) - throw new NotImplementedException("Unknown LVD Section at 0x" + stream.BaseStream.Position.ToString("X")); - - stream.ReadByte(); - if (stream.ReadInt32() > 0) - throw new NotImplementedException("Unknown LVD Section at 0x" + stream.BaseStream.Position.ToString("X")); - - if(VersionMinor > 0xA) + + if (Version > 12) { - stream.ReadByte(); - var shrunkboundsCount = stream.ReadInt32(); - for (int i = 0; i < shrunkboundsCount; i++) + reader.ReadByte(); + uint ptrainerFloatingFloorCount = reader.ReadUInt32(); + for (uint i = 0; i < ptrainerFloatingFloorCount; i++) { - LVDBounds bound = new LVDBounds(); - bound.Read(stream); - ShrunkCameraBounds.Add(bound); - } + LVDPTrainerFloatingFloor ptrainerFloatingFloor = new LVDPTrainerFloatingFloor(); - stream.ReadByte(); - var shrunkblastCount = stream.ReadInt32(); - for (int i = 0; i < shrunkblastCount; i++) - { - LVDBounds blast = new LVDBounds(); - blast.Read(stream); - ShrunkBlastZoneBounds.Add(blast); + ptrainerFloatingFloor.Read(reader); + PTrainerFloatingFloors.Add(ptrainerFloatingFloor); } } + } - if(stream.BaseStream.Length != stream.BaseStream.Position) - { - stream.PrintPosition(); - throw new Exception("Error fully parsing LVD " + stream.BaseStream.Position.ToString("X")); - } + if (Version < 6) + { + return; } - } - public void Save(string FileName) - { - File.WriteAllBytes(FileName, GetData()); + reader.ReadByte(); + uint generalShape2Count = reader.ReadUInt32(); + for (uint i = 0; i < generalShape2Count; i++) + { + LVDGeneralShape2 generalShape2 = new LVDGeneralShape2(); + + generalShape2.Read(reader); + GeneralShapes2D.Add(generalShape2); + } + + reader.ReadByte(); + uint generalShape3Count = reader.ReadUInt32(); + for (uint i = 0; i < generalShape3Count; i++) + { + LVDGeneralShape3 generalShape3 = new LVDGeneralShape3(); + + generalShape3.Read(reader); + GeneralShapes3D.Add(generalShape3); + } + + if (Version < 7) + { + return; + } + + reader.ReadByte(); + if (reader.ReadUInt32() > 0) + { + throw new NotImplementedException("Unknown LVD Section at 0x" + reader.BaseStream.Position.ToString("X")); + } + + if (Version < 8) + { + return; + } + + reader.ReadByte(); + if (reader.ReadUInt32() > 0) + { + throw new NotImplementedException("Unknown LVD Section at 0x" + reader.BaseStream.Position.ToString("X")); + } + + if (Version < 9) + { + return; + } + + reader.ReadByte(); + if (reader.ReadUInt32() > 0) + { + throw new NotImplementedException("Unknown LVD Section at 0x" + reader.BaseStream.Position.ToString("X")); + } + + if (Version < 10) + { + return; + } + + reader.ReadByte(); + if (reader.ReadUInt32() > 0) + { + throw new NotImplementedException("Unknown LVD Section at 0x" + reader.BaseStream.Position.ToString("X")); + } + + if (Version < 11) + { + return; + } + + reader.ReadByte(); + uint shrinkedCameraRegionCount = reader.ReadUInt32(); + for (uint i = 0; i < shrinkedCameraRegionCount; i++) + { + LVDRegion shrinkedCameraRegion = new LVDRegion(); + + shrinkedCameraRegion.Read(reader); + ShrinkedCameraRegions.Add(shrinkedCameraRegion); + } + + reader.ReadByte(); + uint shrinkedDeathRegionCount = reader.ReadUInt32(); + for (uint i = 0; i < shrinkedDeathRegionCount; i++) + { + LVDRegion shrinkedDeathRegion = new LVDRegion(); + + shrinkedDeathRegion.Read(reader); + ShrinkedDeathRegions.Add(shrinkedDeathRegion); + } } - public byte[] GetData() + public void Write(BinaryWriterExt writer) { - MemoryStream stream = new MemoryStream(); + writer.BigEndian = true; - using (BinaryWriterExt writer = new BinaryWriterExt(stream)) + writer.Write(Unknown); + writer.Write(Version); + + writer.Write((byte)1); + writer.Write(Signature.ToCharArray()); + + writer.Write((byte)1); + writer.Write(Collisions.Count); + foreach (var v in Collisions) { - writer.BigEndian = true; + v.Write(writer); + } - writer.Write(Heading); - writer.Write(VersionMinor); - writer.Write(VersionMajor); - writer.Write(Magic.ToCharArray()); + writer.Write((byte)1); + writer.Write(StartPositions.Count); + foreach (var v in StartPositions) + { + v.Write(writer); + } - writer.Write((byte)1); - writer.Write(Collisions.Count); - foreach (var v in Collisions) - v.Write(writer, VersionMinor); + writer.Write((byte)1); + writer.Write(RestartPositions.Count); + foreach (var v in RestartPositions) + { + v.Write(writer); + } - writer.Write((byte)1); - writer.Write(Spawns.Count); - foreach (var v in Spawns) - v.Write(writer); + writer.Write((byte)1); + writer.Write(CameraRegions.Count); + foreach (var v in CameraRegions) + { + v.Write(writer); + } - writer.Write((byte)1); - writer.Write(Respawns.Count); - foreach (var v in Respawns) - v.Write(writer); + writer.Write((byte)1); + writer.Write(DeathRegions.Count); + foreach (var v in DeathRegions) + { + v.Write(writer); + } - writer.Write((byte)1); - writer.Write(CameraBounds.Count); - foreach (var v in CameraBounds) - v.Write(writer); + writer.Write((byte)1); + writer.Write(EnemyGenerators.Count); + foreach (var v in EnemyGenerators) + { + v.Write(writer); + } - writer.Write((byte)1); - writer.Write(BlastZoneBounds.Count); - foreach (var v in BlastZoneBounds) - v.Write(writer); + if (Version < 2) + { + return; + } - writer.Write((byte)1); - writer.Write(EnemyGenerators.Count); - foreach (var v in EnemyGenerators) - v.Write(writer); + writer.Write((byte)1); + writer.Write(0); - writer.Write((byte)1); - writer.Write(0); + if (Version < 3) + { + return; + } - writer.Write((byte)1); - writer.Write(0); + writer.Write((byte)1); + writer.Write(0); - writer.Write((byte)1); - writer.Write(0); + writer.Write((byte)1); + writer.Write(0); - writer.Write((byte)1); - writer.Write(0); + writer.Write((byte)1); + writer.Write(0); - writer.Write((byte)1); - writer.Write(0); + writer.Write((byte)1); + writer.Write(0); - writer.Write((byte)1); - writer.Write(DamageShapes.Count); - foreach (var v in DamageShapes) - v.Write(writer); + if (Version < 4) + { + return; + } + writer.Write((byte)1); + writer.Write(DamageShapes.Count); + foreach (var v in DamageShapes) + { + v.Write(writer); + } + + if (Version < 5) + { + return; + } + + writer.Write((byte)1); + writer.Write(ItemPopupRegions.Count); + foreach (var v in ItemPopupRegions) + { + v.Write(writer); + } + + if (Version > 11) + { writer.Write((byte)1); - writer.Write(ItemSpawners.Count); - foreach (var v in ItemSpawners) + writer.Write(PTrainerRanges.Count); + foreach (var v in PTrainerRanges) + { v.Write(writer); + } - if (VersionMinor > 0xA) + if (Version > 12) { writer.Write((byte)1); - writer.Write(RangeCurves.Count); - foreach (var v in RangeCurves) - v.Write(writer); - - writer.Write((byte)1); - writer.Write(GeneralVectors.Count); - foreach (var v in GeneralVectors) + writer.Write(PTrainerFloatingFloors.Count); + foreach (var v in PTrainerFloatingFloors) + { v.Write(writer); + } } + } - writer.Write((byte)1); - writer.Write(GeneralShapes.Count); - foreach (var v in GeneralShapes) - v.Write(writer); + if (Version < 6) + { + return; + } - writer.Write((byte)1); - writer.Write(GeneralPoints.Count); - foreach (var v in GeneralPoints) - v.Write(writer); + writer.Write((byte)1); + writer.Write(GeneralShapes2D.Count); + foreach (var v in GeneralShapes2D) + { + v.Write(writer); + } - writer.Write((byte)1); - writer.Write(0); + writer.Write((byte)1); + writer.Write(GeneralShapes3D.Count); + foreach (var v in GeneralShapes3D) + { + v.Write(writer); + } - writer.Write((byte)1); - writer.Write(0); + if (Version < 7) + { + return; + } - writer.Write((byte)1); - writer.Write(0); + writer.Write((byte)1); + writer.Write(0); - writer.Write((byte)1); - writer.Write(0); + if (Version < 8) + { + return; + } - if (VersionMinor > 0xA) - { - writer.Write((byte)1); - writer.Write(ShrunkCameraBounds.Count); - foreach (var v in ShrunkCameraBounds) - v.Write(writer); + writer.Write((byte)1); + writer.Write(0); - writer.Write((byte)1); - writer.Write(ShrunkBlastZoneBounds.Count); - foreach (var v in ShrunkBlastZoneBounds) - v.Write(writer); - } + if (Version < 9) + { + return; } - byte[] output = stream.ToArray(); ; - stream.Close(); - stream.Dispose(); - return output; + writer.Write((byte)1); + writer.Write(0); + + if (Version < 10) + { + return; + } + + writer.Write((byte)1); + writer.Write(0); + + if (Version < 11) + { + return; + } + + writer.Write((byte)1); + writer.Write(ShrinkedCameraRegions.Count); + foreach (var v in ShrinkedCameraRegions) + { + v.Write(writer); + } + + writer.Write((byte)1); + writer.Write(ShrinkedDeathRegions.Count); + foreach (var v in ShrinkedDeathRegions) + { + v.Write(writer); + } } } } diff --git a/StudioSB/StudioSB.csproj b/StudioSB/StudioSB.csproj index 19bf71c..1f18866 100644 --- a/StudioSB/StudioSB.csproj +++ b/StudioSB/StudioSB.csproj @@ -85,6 +85,7 @@ + False @@ -221,21 +222,25 @@ - + + - - + - - - - - - - - + + + + + + + + + + + +