Ticket #1034 (closed enhancement: fixed)

Opened 4 years ago

Last modified 4 years ago

Journal Integration

Reported by: asaf Owned by: asaf
Priority: High Milestone: Unspecified by Release Team
Component: Physics Version: Unspecified
Severity: Unspecified Keywords:
Cc: brian, garycmartin, erikos, kne Distribution/OS: Unspecified
Bug Status: Assigned

Description

Save contraptions when closing the activity and load them when opening an old journal entry.

Change History

  Changed 4 years ago by asaf

Planning on using pickling available in pyBox2D version 2.0.2b1

  Changed 4 years ago by asaf

  • status changed from new to accepted

It works now. I have to do some cleanup and a commit to elements the pickling feature. I'll try to commit everything and close the ticket soon.

  Changed 4 years ago by brian

:) excellent!

Let me know if you need any help with the elements commit or elements eggbuilding.

follow-up: ↓ 6   Changed 4 years ago by erikos

As another serialization alternative - we use a lot json (cjson) in sugar and other activities to serialize python objects.  http://git.sugarlabs.org/projects/browse/repos/mainline/blobs/master/model.py#line62

  Changed 4 years ago by asaf

  • status changed from accepted to closed
  • resolution set to fixed

Many weeks of reading resulted in less than 10 lines of code in the activity but here it is. I guess we'll consider changing from pickling to another scheme when necessity arises.

in reply to: ↑ 4   Changed 4 years ago by asaf

  • cc erikos added

Replying to erikos:

As another serialization alternative - we use a lot json (cjson) in sugar and other activities to serialize python objects.  http://git.sugarlabs.org/projects/browse/repos/mainline/blobs/master/model.py#line62

When I try to serialize with

cjson.encode(self.game.world)

I get

EncodeError: object is not JSON encodable

I think it has to do that what I want to serialize is not made of pure-python objects.

  Changed 4 years ago by asaf

  • cc kne added
  • priority changed from Unspecified by Maintainer to High
  • status changed from closed to reopened
  • resolution fixed deleted

Reopened for the sake of forward compatibility.

The plan is to have more control on the savefile format. The suggested implementation is to create a set of classes which structure mimics the structure of the world object. For example:

class Ball:
   pos
   radius
   dynamic
   density
   ...

class Rect:
   pos
   with
   height
   ...

Then create instancees of this objects for each object in the world and put them all in an array and pass that array to cjson.encode . The ideal thing would be to infer this structure from the Add class in elements but that is something to think about a bit more.

  Changed 4 years ago by erikos

Asaf, yes the traceback above suggests that the world object contains non serializable parts. Maybe looking at the pickle code in elements helps.

def pickle_save(self, fn, additional_vars={}):^M
        import cPickle as pickle^M
        self.add.remove_mouseJoint()^M
    ^M
        if not additional_vars and hasattr(self, '_pickle_vars'):^M
            additional_vars=dict((var, getattr(self, var)) for var in self._pickle_vars)^M
^M
        save_values = [self.world, box2d.pickle_fix(self.world, additional_vars, 'save')]^M
^M
        try:^M
            pickle.dump(save_values, open(fn, 'wb'))^M
        except Exception, s:^M
            print 'Pickling failed: ', s^M
            return^M
^M
        print 'Saved to %s' % fn

follow-up: ↓ 10   Changed 4 years ago by kne

SWIG objects are not serializable because they exist both on the Python (the shadow classes) and C++-side (the actual structure itself). As such, the somewhat complicated procedure found in  here was created. It eventually boils everything down to dictionaries when saving and then recreates them upon loading.

Should you take the JSON route of starting from scratch, you will have to take into account things like joints and controllers. When saving, you want to first save the world's shape list. Then enumerate each joint in the world, writing the index of the shape instead of another copy of the shape definition (as you don't want the shape to be created again). Any references to shapes in your code also have to be fixed like this (which is why the pickle_fix method was introduced).

I did my best to introduce the same-named properties in the shapes as the definitions (as of course they weren't present in the original C++ code). I think there was perhaps one property that didn't get changed though, so take a look at the pickling code as a reference.

You might be able to get by with a somewhat hackish method of using the getstate/setstates that I painstakingly (*cough*) wrote for the pickling functionality. Use them to get the necessary data and then use the JSON serializer as you please.

in reply to: ↑ 9 ; follow-up: ↓ 11   Changed 4 years ago by asaf

Replying to kne:


Should you take the JSON route of starting from scratch, you will have to take into account things like joints and controllers. When saving, you want to first save the world's shape list. Then enumerate each joint in the world, writing the index of the shape instead of another copy of the shape definition (as you don't want the shape to be created again). Any references to shapes in your code also have to be fixed like this (which is why the pickle_fix method was introduced).

What do you mean by controllers?
Is there a body index or unique id already defined or should I add one to body.userData ?

in reply to: ↑ 10   Changed 4 years ago by kne

Replying to asaf:

What do you mean by controllers?

 controllers See also the pybox2d buoyancy testbed. If you haven't seen those, you also likely haven't seen the thin line segments, so check those out too.

Is there a body index or unique id already defined or should I add one to body.userData ?

I indexed every body from world.bodyList in my implementation. The body's hash is simply its memory address.

  Changed 4 years ago by asaf

  • status changed from reopened to closed
  • resolution set to fixed

Resolved with JSON format. The save/load functions are implemented at the level of elements. The save/load functions do not support all the features of pybox2d but they support all that the activity requires.

Note: See TracTickets for help on using tickets.