Serialization of bodies with userdata

Topics: User Forum
Nov 12, 2013 at 5:04 PM
Hi all,

When i start the Farseer Serialization it throws an exception 'Sideshooter.Weapon cannot be serialized because it does not have a parameterless constructor', I think it is having problems serializing bodies where the userdata is a GameObject.

I convert these objects to classes that do not inherit from GameObject so I can give them a 'parameterless constructor' and this error goes away. However in my game how would I go about saving the state of the running game if I can't use the Farseer serialization, apart from writing my own serializer which is daunting.

Any thoughts on how to proceed would be welcome!

Cheers.

Jon
Nov 12, 2013 at 6:49 PM
Hi Jon

I never used the "Farseer Serialization", but what's your "GameObject"? Did you mean a GameComponent, or did you roll your own?
Either way, try to declare the class as "serializable" like this:
[Serializable]
public GameObject
{
  public Vector2 Position {get; set;}
}
Maybe that will do the trick.

Cheers,
Richard
Developer
Nov 12, 2013 at 8:41 PM
Like Richard said: Farseer can't do much more than throw your custom user data objects at the serializer. Therefore they of course have to be serializable. That is a c# problem however, not really related to Farseer. An easy solution would be to use Farseers userdata fields just for primitive datatypes (as those have default serializers) e.g. integers which are just an index into some list which holds your actual game data. That still leaves you with the problem of how to restore your actual game data at some point.

The proper way to do it (and if you want to implement some kind of save feature you have to serialize your whole game state anyway at some point) is to (as has already been pointed out) tag your classes with the [Serializable] attribute and to make them implement the ISerializable interface. You can find plenty of information regarding the finer details of how and what to serialize in c# on msdn.
Nov 13, 2013 at 11:16 AM
Edited Nov 13, 2013 at 6:45 PM
Thanks for the replies, in my ignorance I was expecting Farseer serialization to wave a magic wand and serialize everything for me - GameComponents and all. I'll have look into it properly now - and go back to the drawing board again :)

One other question though, if I serialize/deserialize Farseer bodies do they keep the same 'BodyId'?

[EDIT] I can serialize my world now but when I deserialize it a new world is created... how do I then reference my new world? Also do I have to clear my old world?

Cheers.

Jon
Nov 13, 2013 at 7:36 PM
All fixed for now doing the following:-

_game.world.Clear();
_game.world = WorldSerializer.Deserialize(path);

then link the bodies in the freshly loaded world to the existing game components that previously referenced them via their userdata objects.

Onto the next problem.
Nov 18, 2013 at 11:14 AM
Problem isn't fixed. After using world.Clear() and then deserializing I find that body ids in the new world are not the same as when I first generated them, so breaking all the links between my objects. The new body ids are offset by the total amount of bodies in the world prior to serializing, so 4 bodies with ids 0-3 before serializing and after desirialzing I have ids 4-7.
Nov 22, 2013 at 9:12 AM
I tried to simplify my Serialize and then deserialize as much as I could to debug. I start with a new world and add a single body with simple userdata which I can see using the debug view. I serialize but then the deserialize and the game freezes. I'm very confused as to where the problem is, here is my serialized world that fails to desirialize:-

<World Version="3">
<Gravity>0 9.82</Gravity>
<Shapes>
<Shape Type="Circle" Density="5">
  <Radius>0.5</Radius>
  <Position>0 0</Position>
</Shape>
</Shapes>
<Fixtures>
<Fixture Id="0">
  <FilterData>
    <CategoryBits>2</CategoryBits>
    <MaskBits>-3</MaskBits>
    <GroupIndex>0</GroupIndex>
    <CollisionIgnores />
  </FilterData>
  <Friction>0.1</Friction>
  <IsSensor>False</IsSensor>
  <Restitution>0.1</Restitution>
</Fixture>
</Fixtures>
<Bodies>
<Body Type="Dynamic">
  <Active>True</Active>
  <AllowSleep>True</AllowSleep>
  <Angle>0</Angle>
  <AngularDamping>5</AngularDamping>
  <AngularVelocity>0</AngularVelocity>
  <Awake>True</Awake>
  <Bullet>False</Bullet>
  <FixedRotation>False</FixedRotation>
  <LinearDamping>2</LinearDamping>
  <LinearVelocity>0 0.2316178</LinearVelocity>
  <Position>6.453125 2.385633</Position>
  <UserData>
    <Type>FarseerTest.FarseerObject, FarseerTest, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null</Type>
    <Value>
      <FarseerObject>
        <_name>new object10:08</_name>
        <_farseerBodyId>0</_farseerBodyId>
      </FarseerObject>
    </Value>
  </UserData>
  <Bindings>
    <Pair FixtureId="0" ShapeId="0" />
  </Bindings>
</Body>
</Bodies>
<Joints />
</World>

I'm very reluctant to try and read the xml and create bodies using my own methods as I expect that will be a world of pain. Please could someone help or suggest another method of saving the Farseer world and reading it in again.