axiosengine/axios/Common/Serialization.cs

1453 lines
62 KiB
C#

using System;
using System.Collections.Generic;
using System.IO;
using System.Xml;
using System.Xml.Serialization;
using FarseerPhysics.Collision.Shapes;
using FarseerPhysics.Dynamics;
using FarseerPhysics.Dynamics.Joints;
using Microsoft.Xna.Framework;
namespace FarseerPhysics.Common
{
public static class WorldSerializer
{
public static void Serialize(World world, string filename)
{
using (FileStream fs = new FileStream(filename, FileMode.Create))
{
new WorldXmlSerializer().Serialize(world, fs);
}
}
public static void Deserialize(World world, string filename)
{
using (FileStream fs = new FileStream(filename, FileMode.Open))
{
new WorldXmlDeserializer().Deserialize(world, fs);
}
}
public static World Deserialize(string filename)
{
using (FileStream fs = new FileStream(filename, FileMode.Open))
{
return new WorldXmlDeserializer().Deserialize(fs);
}
}
}
///<summary>
///</summary>
public class WorldXmlSerializer
{
private List<Body> _bodies = new List<Body>();
private List<Fixture> _serializedFixtures = new List<Fixture>();
private List<Shape> _serializedShapes = new List<Shape>();
private XmlWriter _writer;
private void SerializeShape(Shape shape)
{
_writer.WriteStartElement("Shape");
_writer.WriteAttributeString("Type", shape.ShapeType.ToString());
switch (shape.ShapeType)
{
case ShapeType.Circle:
{
CircleShape circle = (CircleShape)shape;
_writer.WriteElementString("Radius", circle.Radius.ToString());
WriteElement("Position", circle.Position);
}
break;
case ShapeType.Polygon:
{
PolygonShape poly = (PolygonShape)shape;
_writer.WriteStartElement("Vertices");
foreach (Vector2 v in poly.Vertices)
WriteElement("Vertex", v);
_writer.WriteEndElement();
WriteElement("Centroid", poly.MassData.Centroid);
}
break;
case ShapeType.Edge:
{
EdgeShape poly = (EdgeShape)shape;
WriteElement("Vertex1", poly.Vertex1);
WriteElement("Vertex2", poly.Vertex2);
}
break;
default:
throw new Exception();
}
_writer.WriteEndElement();
}
private void SerializeFixture(Fixture fixture)
{
_writer.WriteStartElement("Fixture");
_writer.WriteElementString("Shape", FindShapeIndex(fixture.Shape).ToString());
_writer.WriteElementString("Density", fixture.Shape.Density.ToString());
_writer.WriteStartElement("FilterData");
_writer.WriteElementString("CategoryBits", ((int)fixture.CollisionCategories).ToString());
_writer.WriteElementString("MaskBits", ((int)fixture.CollidesWith).ToString());
_writer.WriteElementString("GroupIndex", fixture.CollisionGroup.ToString());
_writer.WriteEndElement();
_writer.WriteElementString("Friction", fixture.Friction.ToString());
_writer.WriteElementString("IsSensor", fixture.IsSensor.ToString());
_writer.WriteElementString("Restitution", fixture.Restitution.ToString());
if (fixture.UserData != null)
{
_writer.WriteStartElement("UserData");
WriteDynamicType(fixture.UserData.GetType(), fixture.UserData);
_writer.WriteEndElement();
}
_writer.WriteEndElement();
}
private void SerializeBody(Body body)
{
_writer.WriteStartElement("Body");
_writer.WriteAttributeString("Type", body.BodyType.ToString());
_writer.WriteElementString("Active", body.Enabled.ToString());
_writer.WriteElementString("AllowSleep", body.SleepingAllowed.ToString());
_writer.WriteElementString("Angle", body.Rotation.ToString());
_writer.WriteElementString("AngularDamping", body.AngularDamping.ToString());
_writer.WriteElementString("AngularVelocity", body.AngularVelocity.ToString());
_writer.WriteElementString("Awake", body.Awake.ToString());
_writer.WriteElementString("Bullet", body.IsBullet.ToString());
_writer.WriteElementString("FixedRotation", body.FixedRotation.ToString());
_writer.WriteElementString("LinearDamping", body.LinearDamping.ToString());
WriteElement("LinearVelocity", body.LinearVelocity);
WriteElement("Position", body.Position);
if (body.UserData != null)
{
_writer.WriteStartElement("UserData");
WriteDynamicType(body.UserData.GetType(), body.UserData);
_writer.WriteEndElement();
}
_writer.WriteStartElement("Fixtures");
for (int i = 0; i < body.FixtureList.Count; i++)
{
_writer.WriteElementString("ID", FindFixtureIndex(body.FixtureList[i]).ToString());
}
_writer.WriteEndElement();
_writer.WriteEndElement();
}
private void SerializeJoint(Joint joint)
{
if (joint.IsFixedType())
return;
_writer.WriteStartElement("Joint");
_writer.WriteAttributeString("Type", joint.JointType.ToString());
WriteElement("BodyA", FindBodyIndex(joint.BodyA));
WriteElement("BodyB", FindBodyIndex(joint.BodyB));
WriteElement("CollideConnected", joint.CollideConnected);
WriteElement("Breakpoint", joint.Breakpoint);
if (joint.UserData != null)
{
_writer.WriteStartElement("UserData");
WriteDynamicType(joint.UserData.GetType(), joint.UserData);
_writer.WriteEndElement();
}
switch (joint.JointType)
{
case JointType.Distance:
{
DistanceJoint djd = (DistanceJoint)joint;
WriteElement("DampingRatio", djd.DampingRatio);
WriteElement("FrequencyHz", djd.Frequency);
WriteElement("Length", djd.Length);
WriteElement("LocalAnchorA", djd.LocalAnchorA);
WriteElement("LocalAnchorB", djd.LocalAnchorB);
}
break;
case JointType.Friction:
{
FrictionJoint fjd = (FrictionJoint)joint;
WriteElement("LocalAnchorA", fjd.LocalAnchorA);
WriteElement("LocalAnchorB", fjd.LocalAnchorB);
WriteElement("MaxForce", fjd.MaxForce);
WriteElement("MaxTorque", fjd.MaxTorque);
}
break;
case JointType.Gear:
throw new Exception("Gear joint not supported by serialization");
case JointType.Line:
{
LineJoint ljd = (LineJoint)joint;
WriteElement("EnableMotor", ljd.MotorEnabled);
WriteElement("LocalAnchorA", ljd.LocalAnchorA);
WriteElement("LocalAnchorB", ljd.LocalAnchorB);
WriteElement("MotorSpeed", ljd.MotorSpeed);
WriteElement("DampingRatio", ljd.DampingRatio);
WriteElement("MaxMotorTorque", ljd.MaxMotorTorque);
WriteElement("FrequencyHz", ljd.Frequency);
WriteElement("LocalXAxis", ljd.LocalXAxis);
}
break;
case JointType.Prismatic:
{
PrismaticJoint pjd = (PrismaticJoint)joint;
//NOTE: Does not conform with Box2DScene
WriteElement("EnableLimit", pjd.LimitEnabled);
WriteElement("EnableMotor", pjd.MotorEnabled);
WriteElement("LocalAnchorA", pjd.LocalAnchorA);
WriteElement("LocalAnchorB", pjd.LocalAnchorB);
WriteElement("LocalXAxis1", pjd.LocalXAxis1);
WriteElement("LowerTranslation", pjd.LowerLimit);
WriteElement("UpperTranslation", pjd.UpperLimit);
WriteElement("MaxMotorForce", pjd.MaxMotorForce);
WriteElement("MotorSpeed", pjd.MotorSpeed);
}
break;
case JointType.Pulley:
{
PulleyJoint pjd = (PulleyJoint)joint;
WriteElement("GroundAnchorA", pjd.GroundAnchorA);
WriteElement("GroundAnchorB", pjd.GroundAnchorB);
WriteElement("LengthA", pjd.LengthA);
WriteElement("LengthB", pjd.LengthB);
WriteElement("LocalAnchorA", pjd.LocalAnchorA);
WriteElement("LocalAnchorB", pjd.LocalAnchorB);
WriteElement("MaxLengthA", pjd.MaxLengthA);
WriteElement("MaxLengthB", pjd.MaxLengthB);
WriteElement("Ratio", pjd.Ratio);
}
break;
case JointType.Revolute:
{
RevoluteJoint rjd = (RevoluteJoint)joint;
WriteElement("EnableLimit", rjd.LimitEnabled);
WriteElement("EnableMotor", rjd.MotorEnabled);
WriteElement("LocalAnchorA", rjd.LocalAnchorA);
WriteElement("LocalAnchorB", rjd.LocalAnchorB);
WriteElement("LowerAngle", rjd.LowerLimit);
WriteElement("MaxMotorTorque", rjd.MaxMotorTorque);
WriteElement("MotorSpeed", rjd.MotorSpeed);
WriteElement("ReferenceAngle", rjd.ReferenceAngle);
WriteElement("UpperAngle", rjd.UpperLimit);
}
break;
case JointType.Weld:
{
WeldJoint wjd = (WeldJoint)joint;
WriteElement("LocalAnchorA", wjd.LocalAnchorA);
WriteElement("LocalAnchorB", wjd.LocalAnchorB);
}
break;
//
// Not part of Box2DScene
//
case JointType.Rope:
{
RopeJoint rjd = (RopeJoint)joint;
WriteElement("LocalAnchorA", rjd.LocalAnchorA);
WriteElement("LocalAnchorB", rjd.LocalAnchorB);
WriteElement("MaxLength", rjd.MaxLength);
}
break;
case JointType.Angle:
{
AngleJoint aj = (AngleJoint)joint;
WriteElement("BiasFactor", aj.BiasFactor);
WriteElement("MaxImpulse", aj.MaxImpulse);
WriteElement("Softness", aj.Softness);
WriteElement("TargetAngle", aj.TargetAngle);
}
break;
case JointType.Slider:
{
SliderJoint sliderJoint = (SliderJoint)joint;
WriteElement("DampingRatio", sliderJoint.DampingRatio);
WriteElement("FrequencyHz", sliderJoint.Frequency);
WriteElement("MaxLength", sliderJoint.MaxLength);
WriteElement("MinLength", sliderJoint.MinLength);
WriteElement("LocalAnchorA", sliderJoint.LocalAnchorA);
WriteElement("LocalAnchorB", sliderJoint.LocalAnchorB);
}
break;
default:
throw new Exception("Joint not supported");
}
_writer.WriteEndElement();
}
private void WriteDynamicType(Type type, object val)
{
_writer.WriteElementString("Type", type.FullName);
_writer.WriteStartElement("Value");
XmlSerializer serializer = new XmlSerializer(type);
XmlSerializerNamespaces xmlnsEmpty = new XmlSerializerNamespaces();
xmlnsEmpty.Add("", "");
serializer.Serialize(_writer, val, xmlnsEmpty);
_writer.WriteEndElement();
}
private void WriteElement(string name, Vector2 vec)
{
_writer.WriteElementString(name, vec.X + " " + vec.Y);
}
private void WriteElement(string name, int val)
{
_writer.WriteElementString(name, val.ToString());
}
private void WriteElement(string name, bool val)
{
_writer.WriteElementString(name, val.ToString());
}
private void WriteElement(string name, float val)
{
_writer.WriteElementString(name, val.ToString());
}
public void Serialize(World world, Stream stream)
{
XmlWriterSettings settings = new XmlWriterSettings();
settings.Indent = true;
settings.NewLineOnAttributes = false;
settings.OmitXmlDeclaration = true;
_writer = XmlWriter.Create(stream, settings);
_writer.WriteStartElement("World");
_writer.WriteAttributeString("Version", "2");
WriteElement("Gravity", world.Gravity);
_writer.WriteStartElement("Shapes");
for (int i = 0; i < world.BodyList.Count; i++)
{
Body body = world.BodyList[i];
for (int j = 0; j < body.FixtureList.Count; j++)
{
Fixture fixture = body.FixtureList[j];
bool alreadyThere = false;
for (int k = 0; k < _serializedShapes.Count; k++)
{
Shape s2 = _serializedShapes[k];
if (fixture.Shape.CompareTo(s2))
{
alreadyThere = true;
break;
}
}
if (!alreadyThere)
{
SerializeShape(fixture.Shape);
_serializedShapes.Add(fixture.Shape);
}
}
}
_writer.WriteEndElement();
_writer.WriteStartElement("Fixtures");
for (int i = 0; i < world.BodyList.Count; i++)
{
Body body = world.BodyList[i];
for (int j = 0; j < body.FixtureList.Count; j++)
{
Fixture fixture = body.FixtureList[j];
bool alreadyThere = false;
for (int k = 0; k < _serializedFixtures.Count; k++)
{
Fixture f2 = _serializedFixtures[k];
if (fixture.CompareTo(f2))
{
alreadyThere = true;
break;
}
}
if (!alreadyThere)
{
SerializeFixture(fixture);
_serializedFixtures.Add(fixture);
}
}
}
_writer.WriteEndElement();
_writer.WriteStartElement("Bodies");
for (int i = 0; i < world.BodyList.Count; i++)
{
Body body = world.BodyList[i];
_bodies.Add(body);
SerializeBody(body);
}
_writer.WriteEndElement();
_writer.WriteStartElement("Joints");
for (int i = 0; i < world.JointList.Count; i++)
{
Joint joint = world.JointList[i];
SerializeJoint(joint);
}
_writer.WriteEndElement();
_writer.WriteEndElement();
_writer.Flush();
_writer.Close();
}
private int FindBodyIndex(Body body)
{
for (int i = 0; i < _bodies.Count; ++i)
if (_bodies[i] == body)
return i;
return -1;
}
private int FindFixtureIndex(Fixture fixture)
{
for (int i = 0; i < _serializedFixtures.Count; ++i)
{
if (_serializedFixtures[i].CompareTo(fixture))
return i;
}
return -1;
}
private int FindShapeIndex(Shape shape)
{
for (int i = 0; i < _serializedShapes.Count; ++i)
{
if (_serializedShapes[i].CompareTo(shape))
return i;
}
return -1;
}
}
public class WorldXmlDeserializer
{
private List<Body> _bodies = new List<Body>();
private List<Fixture> _fixtures = new List<Fixture>();
private List<Joint> _joints = new List<Joint>();
private List<Shape> _shapes = new List<Shape>();
public World Deserialize(Stream stream)
{
World world = new World(Vector2.Zero);
Deserialize(world, stream);
return world;
}
public void Deserialize(World world, Stream stream)
{
world.Clear();
XMLFragmentElement root = XMLFragmentParser.LoadFromStream(stream);
if (root.Name.ToLower() != "world")
throw new Exception();
foreach (XMLFragmentElement main in root.Elements)
{
if (main.Name.ToLower() == "gravity")
{
world.Gravity = ReadVector(main);
}
}
foreach (XMLFragmentElement shapeElement in root.Elements)
{
if (shapeElement.Name.ToLower() == "shapes")
{
foreach (XMLFragmentElement n in shapeElement.Elements)
{
if (n.Name.ToLower() != "shape")
throw new Exception();
ShapeType type = (ShapeType)Enum.Parse(typeof(ShapeType), n.Attributes[0].Value, true);
switch (type)
{
case ShapeType.Circle:
{
CircleShape shape = new CircleShape();
foreach (XMLFragmentElement sn in n.Elements)
{
switch (sn.Name.ToLower())
{
case "radius":
shape.Radius = float.Parse(sn.Value);
break;
case "position":
shape.Position = ReadVector(sn);
break;
default:
throw new Exception();
}
}
_shapes.Add(shape);
}
break;
case ShapeType.Polygon:
{
PolygonShape shape = new PolygonShape();
foreach (XMLFragmentElement sn in n.Elements)
{
switch (sn.Name.ToLower())
{
case "vertices":
{
List<Vector2> verts = new List<Vector2>();
foreach (XMLFragmentElement vert in sn.Elements)
verts.Add(ReadVector(vert));
shape.Set(new Vertices(verts.ToArray()));
}
break;
case "centroid":
shape.MassData.Centroid = ReadVector(sn);
break;
}
}
_shapes.Add(shape);
}
break;
case ShapeType.Edge:
{
EdgeShape shape = new EdgeShape();
foreach (XMLFragmentElement sn in n.Elements)
{
switch (sn.Name.ToLower())
{
case "hasvertex0":
shape.HasVertex0 = bool.Parse(sn.Value);
break;
case "hasvertex3":
shape.HasVertex0 = bool.Parse(sn.Value);
break;
case "vertex0":
shape.Vertex0 = ReadVector(sn);
break;
case "vertex1":
shape.Vertex1 = ReadVector(sn);
break;
case "vertex2":
shape.Vertex2 = ReadVector(sn);
break;
case "vertex3":
shape.Vertex3 = ReadVector(sn);
break;
default:
throw new Exception();
}
}
_shapes.Add(shape);
}
break;
}
}
}
}
foreach (XMLFragmentElement fixtureElement in root.Elements)
{
if (fixtureElement.Name.ToLower() == "fixtures")
{
foreach (XMLFragmentElement n in fixtureElement.Elements)
{
Fixture fixture = new Fixture();
if (n.Name.ToLower() != "fixture")
throw new Exception();
foreach (XMLFragmentElement sn in n.Elements)
{
switch (sn.Name.ToLower())
{
case "shape":
fixture.Shape = _shapes[int.Parse(sn.Value)];
break;
case "density":
fixture.Shape.Density = float.Parse(sn.Value);
break;
case "filterdata":
foreach (XMLFragmentElement ssn in sn.Elements)
{
switch (ssn.Name.ToLower())
{
case "categorybits":
fixture._collisionCategories = (Category)int.Parse(ssn.Value);
break;
case "maskbits":
fixture._collidesWith = (Category)int.Parse(ssn.Value);
break;
case "groupindex":
fixture._collisionGroup = short.Parse(ssn.Value);
break;
}
}
break;
case "friction":
fixture.Friction = float.Parse(sn.Value);
break;
case "issensor":
fixture.IsSensor = bool.Parse(sn.Value);
break;
case "restitution":
fixture.Restitution = float.Parse(sn.Value);
break;
case "userdata":
fixture.UserData = ReadSimpleType(sn, null, false);
break;
}
}
_fixtures.Add(fixture);
}
}
}
foreach (XMLFragmentElement bodyElement in root.Elements)
{
if (bodyElement.Name.ToLower() == "bodies")
{
foreach (XMLFragmentElement n in bodyElement.Elements)
{
Body body = new Body(world);
if (n.Name.ToLower() != "body")
throw new Exception();
body.BodyType = (BodyType)Enum.Parse(typeof(BodyType), n.Attributes[0].Value, true);
foreach (XMLFragmentElement sn in n.Elements)
{
switch (sn.Name.ToLower())
{
case "active":
if (bool.Parse(sn.Value))
body.Flags |= BodyFlags.Enabled;
else
body.Flags &= ~BodyFlags.Enabled;
break;
case "allowsleep":
body.SleepingAllowed = bool.Parse(sn.Value);
break;
case "angle":
{
Vector2 position = body.Position;
body.SetTransformIgnoreContacts(ref position, float.Parse(sn.Value));
}
break;
case "angulardamping":
body.AngularDamping = float.Parse(sn.Value);
break;
case "angularvelocity":
body.AngularVelocity = float.Parse(sn.Value);
break;
case "awake":
body.Awake = bool.Parse(sn.Value);
break;
case "bullet":
body.IsBullet = bool.Parse(sn.Value);
break;
case "fixedrotation":
body.FixedRotation = bool.Parse(sn.Value);
break;
case "lineardamping":
body.LinearDamping = float.Parse(sn.Value);
break;
case "linearvelocity":
body.LinearVelocity = ReadVector(sn);
break;
case "position":
{
float rotation = body.Rotation;
Vector2 position = ReadVector(sn);
body.SetTransformIgnoreContacts(ref position, rotation);
}
break;
case "userdata":
body.UserData = ReadSimpleType(sn, null, false);
break;
case "fixtures":
{
foreach (XMLFragmentElement v in sn.Elements)
{
Fixture blueprint = _fixtures[int.Parse(v.Value)];
Fixture f = new Fixture(body, blueprint.Shape);
f.Restitution = blueprint.Restitution;
f.UserData = blueprint.UserData;
f.Friction = blueprint.Friction;
f.CollidesWith = blueprint.CollidesWith;
f.CollisionCategories = blueprint.CollisionCategories;
f.CollisionGroup = blueprint.CollisionGroup;
}
break;
}
}
}
_bodies.Add(body);
}
}
}
foreach (XMLFragmentElement jointElement in root.Elements)
{
if (jointElement.Name.ToLower() == "joints")
{
foreach (XMLFragmentElement n in jointElement.Elements)
{
Joint joint;
if (n.Name.ToLower() != "joint")
throw new Exception();
JointType type = (JointType)Enum.Parse(typeof(JointType), n.Attributes[0].Value, true);
int bodyAIndex = -1, bodyBIndex = -1;
bool collideConnected = false;
object userData = null;
foreach (XMLFragmentElement sn in n.Elements)
{
switch (sn.Name.ToLower())
{
case "bodya":
bodyAIndex = int.Parse(sn.Value);
break;
case "bodyb":
bodyBIndex = int.Parse(sn.Value);
break;
case "collideconnected":
collideConnected = bool.Parse(sn.Value);
break;
case "userdata":
userData = ReadSimpleType(sn, null, false);
break;
}
}
Body bodyA = _bodies[bodyAIndex];
Body bodyB = _bodies[bodyBIndex];
switch (type)
{
case JointType.Distance:
joint = new DistanceJoint();
break;
case JointType.Friction:
joint = new FrictionJoint();
break;
case JointType.Line:
joint = new LineJoint();
break;
case JointType.Prismatic:
joint = new PrismaticJoint();
break;
case JointType.Pulley:
joint = new PulleyJoint();
break;
case JointType.Revolute:
joint = new RevoluteJoint();
break;
case JointType.Weld:
joint = new WeldJoint();
break;
case JointType.Rope:
joint = new RopeJoint();
break;
case JointType.Angle:
joint = new AngleJoint();
break;
case JointType.Slider:
joint = new SliderJoint();
break;
case JointType.Gear:
throw new Exception("GearJoint is not supported.");
default:
throw new Exception("Invalid or unsupported joint.");
}
joint.CollideConnected = collideConnected;
joint.UserData = userData;
joint.BodyA = bodyA;
joint.BodyB = bodyB;
_joints.Add(joint);
world.AddJoint(joint);
foreach (XMLFragmentElement sn in n.Elements)
{
// check for specific nodes
switch (type)
{
case JointType.Distance:
{
switch (sn.Name.ToLower())
{
case "dampingratio":
((DistanceJoint)joint).DampingRatio = float.Parse(sn.Value);
break;
case "frequencyhz":
((DistanceJoint)joint).Frequency = float.Parse(sn.Value);
break;
case "length":
((DistanceJoint)joint).Length = float.Parse(sn.Value);
break;
case "localanchora":
((DistanceJoint)joint).LocalAnchorA = ReadVector(sn);
break;
case "localanchorb":
((DistanceJoint)joint).LocalAnchorB = ReadVector(sn);
break;
}
}
break;
case JointType.Friction:
{
switch (sn.Name.ToLower())
{
case "localanchora":
((FrictionJoint)joint).LocalAnchorA = ReadVector(sn);
break;
case "localanchorb":
((FrictionJoint)joint).LocalAnchorB = ReadVector(sn);
break;
case "maxforce":
((FrictionJoint)joint).MaxForce = float.Parse(sn.Value);
break;
case "maxtorque":
((FrictionJoint)joint).MaxTorque = float.Parse(sn.Value);
break;
}
}
break;
case JointType.Line:
{
switch (sn.Name.ToLower())
{
case "enablemotor":
((LineJoint)joint).MotorEnabled = bool.Parse(sn.Value);
break;
case "localanchora":
((LineJoint)joint).LocalAnchorA = ReadVector(sn);
break;
case "localanchorb":
((LineJoint)joint).LocalAnchorB = ReadVector(sn);
break;
case "motorspeed":
((LineJoint)joint).MotorSpeed = float.Parse(sn.Value);
break;
case "dampingratio":
((LineJoint)joint).DampingRatio = float.Parse(sn.Value);
break;
case "maxmotortorque":
((LineJoint)joint).MaxMotorTorque = float.Parse(sn.Value);
break;
case "frequencyhz":
((LineJoint)joint).Frequency = float.Parse(sn.Value);
break;
case "localxaxis":
((LineJoint)joint).LocalXAxis = ReadVector(sn);
break;
}
}
break;
case JointType.Prismatic:
{
switch (sn.Name.ToLower())
{
case "enablelimit":
((PrismaticJoint)joint).LimitEnabled = bool.Parse(sn.Value);
break;
case "enablemotor":
((PrismaticJoint)joint).MotorEnabled = bool.Parse(sn.Value);
break;
case "localanchora":
((PrismaticJoint)joint).LocalAnchorA = ReadVector(sn);
break;
case "localanchorb":
((PrismaticJoint)joint).LocalAnchorB = ReadVector(sn);
break;
case "local1axis1":
((PrismaticJoint)joint).LocalXAxis1 = ReadVector(sn);
break;
case "maxmotorforce":
((PrismaticJoint)joint).MaxMotorForce = float.Parse(sn.Value);
break;
case "motorspeed":
((PrismaticJoint)joint).MotorSpeed = float.Parse(sn.Value);
break;
case "lowertranslation":
((PrismaticJoint)joint).LowerLimit = float.Parse(sn.Value);
break;
case "uppertranslation":
((PrismaticJoint)joint).UpperLimit = float.Parse(sn.Value);
break;
case "referenceangle":
((PrismaticJoint)joint).ReferenceAngle = float.Parse(sn.Value);
break;
}
}
break;
case JointType.Pulley:
{
switch (sn.Name.ToLower())
{
case "groundanchora":
((PulleyJoint)joint).GroundAnchorA = ReadVector(sn);
break;
case "groundanchorb":
((PulleyJoint)joint).GroundAnchorB = ReadVector(sn);
break;
case "lengtha":
((PulleyJoint)joint).LengthA = float.Parse(sn.Value);
break;
case "lengthb":
((PulleyJoint)joint).LengthB = float.Parse(sn.Value);
break;
case "localanchora":
((PulleyJoint)joint).LocalAnchorA = ReadVector(sn);
break;
case "localanchorb":
((PulleyJoint)joint).LocalAnchorB = ReadVector(sn);
break;
case "maxlengtha":
((PulleyJoint)joint).MaxLengthA = float.Parse(sn.Value);
break;
case "maxlengthb":
((PulleyJoint)joint).MaxLengthB = float.Parse(sn.Value);
break;
case "ratio":
((PulleyJoint)joint).Ratio = float.Parse(sn.Value);
break;
}
}
break;
case JointType.Revolute:
{
switch (sn.Name.ToLower())
{
case "enablelimit":
((RevoluteJoint)joint).LimitEnabled = bool.Parse(sn.Value);
break;
case "enablemotor":
((RevoluteJoint)joint).MotorEnabled = bool.Parse(sn.Value);
break;
case "localanchora":
((RevoluteJoint)joint).LocalAnchorA = ReadVector(sn);
break;
case "localanchorb":
((RevoluteJoint)joint).LocalAnchorB = ReadVector(sn);
break;
case "maxmotortorque":
((RevoluteJoint)joint).MaxMotorTorque = float.Parse(sn.Value);
break;
case "motorspeed":
((RevoluteJoint)joint).MotorSpeed = float.Parse(sn.Value);
break;
case "lowerangle":
((RevoluteJoint)joint).LowerLimit = float.Parse(sn.Value);
break;
case "upperangle":
((RevoluteJoint)joint).UpperLimit = float.Parse(sn.Value);
break;
case "referenceangle":
((RevoluteJoint)joint).ReferenceAngle = float.Parse(sn.Value);
break;
}
}
break;
case JointType.Weld:
{
switch (sn.Name.ToLower())
{
case "localanchora":
((WeldJoint)joint).LocalAnchorA = ReadVector(sn);
break;
case "localanchorb":
((WeldJoint)joint).LocalAnchorB = ReadVector(sn);
break;
}
}
break;
case JointType.Rope:
{
switch (sn.Name.ToLower())
{
case "localanchora":
((RopeJoint)joint).LocalAnchorA = ReadVector(sn);
break;
case "localanchorb":
((RopeJoint)joint).LocalAnchorB = ReadVector(sn);
break;
case "maxlength":
((RopeJoint)joint).MaxLength = float.Parse(sn.Value);
break;
}
}
break;
case JointType.Gear:
throw new Exception("Gear joint is unsupported");
case JointType.Angle:
{
switch (sn.Name.ToLower())
{
case "biasfactor":
((AngleJoint)joint).BiasFactor = float.Parse(sn.Value);
break;
case "maximpulse":
((AngleJoint)joint).MaxImpulse = float.Parse(sn.Value);
break;
case "softness":
((AngleJoint)joint).Softness = float.Parse(sn.Value);
break;
case "targetangle":
((AngleJoint)joint).TargetAngle = float.Parse(sn.Value);
break;
}
}
break;
case JointType.Slider:
{
switch (sn.Name.ToLower())
{
case "dampingratio":
((SliderJoint)joint).DampingRatio = float.Parse(sn.Value);
break;
case "frequencyhz":
((SliderJoint)joint).Frequency = float.Parse(sn.Value);
break;
case "maxlength":
((SliderJoint)joint).MaxLength = float.Parse(sn.Value);
break;
case "minlength":
((SliderJoint)joint).MinLength = float.Parse(sn.Value);
break;
case "localanchora":
((SliderJoint)joint).LocalAnchorA = ReadVector(sn);
break;
case "localanchorb":
((SliderJoint)joint).LocalAnchorB = ReadVector(sn);
break;
}
}
break;
}
}
}
}
}
}
private Vector2 ReadVector(XMLFragmentElement node)
{
string[] values = node.Value.Split(' ');
return new Vector2(float.Parse(values[0]), float.Parse(values[1]));
}
private object ReadSimpleType(XMLFragmentElement node, Type type, bool outer)
{
if (type == null)
return ReadSimpleType(node.Elements[1], Type.GetType(node.Elements[0].Value), outer);
XmlSerializer serializer = new XmlSerializer(type);
XmlSerializerNamespaces xmlnsEmpty = new XmlSerializerNamespaces();
xmlnsEmpty.Add("", "");
using (MemoryStream stream = new MemoryStream())
{
StreamWriter writer = new StreamWriter(stream);
{
writer.Write((outer) ? node.OuterXml : node.InnerXml);
writer.Flush();
stream.Position = 0;
}
XmlReaderSettings settings = new XmlReaderSettings();
settings.ConformanceLevel = ConformanceLevel.Fragment;
return serializer.Deserialize(XmlReader.Create(stream, settings));
}
}
}
#region XMLFragment
public class XMLFragmentAttribute
{
public string Name { get; set; }
public string Value { get; set; }
}
public class XMLFragmentElement
{
private List<XMLFragmentAttribute> _attributes = new List<XMLFragmentAttribute>();
private List<XMLFragmentElement> _elements = new List<XMLFragmentElement>();
public IList<XMLFragmentElement> Elements
{
get { return _elements; }
}
public IList<XMLFragmentAttribute> Attributes
{
get { return _attributes; }
}
public string Name { get; set; }
public string Value { get; set; }
public string OuterXml { get; set; }
public string InnerXml { get; set; }
}
public class XMLFragmentException : Exception
{
public XMLFragmentException()
{
}
public XMLFragmentException(string message)
: base(message)
{
}
public XMLFragmentException(string message, Exception inner)
: base(message, inner)
{
}
}
public class FileBuffer
{
public FileBuffer(Stream stream)
{
using (StreamReader sr = new StreamReader(stream))
Buffer = sr.ReadToEnd();
Position = 0;
}
public string Buffer { get; set; }
public int Position { get; set; }
public int Length
{
get { return Buffer.Length; }
}
public char Next
{
get
{
char c = Buffer[Position];
Position++;
return c;
}
}
public char Peek
{
get { return Buffer[Position]; }
}
public bool EndOfBuffer
{
get { return Position == Length; }
}
}
public class XMLFragmentParser
{
private static List<char> _punctuation = new List<char> { '/', '<', '>', '=' };
private FileBuffer _buffer;
private XMLFragmentElement _rootNode;
public XMLFragmentParser(Stream stream)
{
Load(stream);
}
public XMLFragmentParser(string fileName)
{
using (FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read))
Load(fs);
}
public XMLFragmentElement RootNode
{
get { return _rootNode; }
}
public void Load(Stream stream)
{
_buffer = new FileBuffer(stream);
}
public static XMLFragmentElement LoadFromFile(string fileName)
{
XMLFragmentParser x = new XMLFragmentParser(fileName);
x.Parse();
return x.RootNode;
}
public static XMLFragmentElement LoadFromStream(Stream stream)
{
XMLFragmentParser x = new XMLFragmentParser(stream);
x.Parse();
return x.RootNode;
}
private string NextToken()
{
string str = "";
bool _done = false;
while (true)
{
char c = _buffer.Next;
if (_punctuation.Contains(c))
{
if (str != "")
{
_buffer.Position--;
break;
}
_done = true;
}
else if (char.IsWhiteSpace(c))
{
if (str != "")
break;
else
continue;
}
str += c;
if (_done)
break;
}
str = TrimControl(str);
// Trim quotes from start and end
if (str[0] == '\"')
str = str.Remove(0, 1);
if (str[str.Length - 1] == '\"')
str = str.Remove(str.Length - 1, 1);
return str;
}
private string PeekToken()
{
int oldPos = _buffer.Position;
string str = NextToken();
_buffer.Position = oldPos;
return str;
}
private string ReadUntil(char c)
{
string str = "";
while (true)
{
char ch = _buffer.Next;
if (ch == c)
{
_buffer.Position--;
break;
}
str += ch;
}
// Trim quotes from start and end
if (str[0] == '\"')
str = str.Remove(0, 1);
if (str[str.Length - 1] == '\"')
str = str.Remove(str.Length - 1, 1);
return str;
}
private string TrimControl(string str)
{
string newStr = str;
// Trim control characters
int i = 0;
while (true)
{
if (i == newStr.Length)
break;
if (char.IsControl(newStr[i]))
newStr = newStr.Remove(i, 1);
else
i++;
}
return newStr;
}
private string TrimTags(string outer)
{
int start = outer.IndexOf('>') + 1;
int end = outer.LastIndexOf('<');
return TrimControl(outer.Substring(start, end - start));
}
public XMLFragmentElement TryParseNode()
{
if (_buffer.EndOfBuffer)
return null;
int startOuterXml = _buffer.Position;
string token = NextToken();
if (token != "<")
throw new XMLFragmentException("Expected \"<\", got " + token);
XMLFragmentElement element = new XMLFragmentElement();
element.Name = NextToken();
while (true)
{
token = NextToken();
if (token == ">")
break;
else if (token == "/") // quick-exit case
{
NextToken();
element.OuterXml =
TrimControl(_buffer.Buffer.Substring(startOuterXml, _buffer.Position - startOuterXml)).Trim();
element.InnerXml = "";
return element;
}
else
{
XMLFragmentAttribute attribute = new XMLFragmentAttribute();
attribute.Name = token;
if ((token = NextToken()) != "=")
throw new XMLFragmentException("Expected \"=\", got " + token);
attribute.Value = NextToken();
element.Attributes.Add(attribute);
}
}
while (true)
{
int oldPos = _buffer.Position; // for restoration below
token = NextToken();
if (token == "<")
{
token = PeekToken();
if (token == "/") // finish element
{
NextToken(); // skip the / again
token = NextToken();
NextToken(); // skip >
element.OuterXml =
TrimControl(_buffer.Buffer.Substring(startOuterXml, _buffer.Position - startOuterXml)).Trim();
element.InnerXml = TrimTags(element.OuterXml);
if (token != element.Name)
throw new XMLFragmentException("Mismatched element pairs: \"" + element.Name + "\" vs \"" +
token + "\"");
break;
}
else
{
_buffer.Position = oldPos;
element.Elements.Add(TryParseNode());
}
}
else
{
// value, probably
_buffer.Position = oldPos;
element.Value = ReadUntil('<');
}
}
return element;
}
public void Parse()
{
_rootNode = TryParseNode();
if (_rootNode == null)
throw new XMLFragmentException("Unable to load root node");
}
}
#endregion
}