Bye Panda3d, Hi Soya3d


Soya3d 0.7 was recently released. It's a high-level 3d game engine for Python written in Pyrex (which is also awesome).



A while ago I was considering Panda3d, mostly because Soya3d refused to work on my system at the time. I discovered that Panda3d was a typical, gigantic, terribly over- and mis-designed framework, but of all frameworks that have these traits, it is the only one that had a (seemingly) complete Python interface with a real game written entirely in Python making use of it. That excited me, so I put some time into figuring it out.



Well, long story short, Panda3d quickly crushed my soul with its horrible installation process and its bad support on Linux, and I got bored with the whole idea of 3d engines for another few months. With the release of Soya3d 0.7, however, it no longer crashes on my system -- and in a few days of playing around, I am elbows-deep in really fun 3d stuff (as opposed to knee-deep in a pile of installation and deployment rubble).



The fact that Soya3d is GPL saddens me, but I don't actually have a specific need to put my software that uses it under a different license - and if I ever do, I figure I can put the core game itself under the GPL and have it load non-GPL plugins and data, a la the Linux kernel.



The best thing about Soya3d is that it's written 100% *for Python*. It's very easy to install, as is most other Python-based software, and the API is really easy to use. It doesn't have great API docs (although it has rather good examples) and is lacking some features like cell shading and shadows, but the Pythonicness totally dwarves these negatives.



Modifying (upgrading) pickles without instantiating real app objects



While changing Infogreater from using Pickle as its data format to a home-made XML dialect, I of course wanted to upgrade my old pickle data to the new format. The problem was, though, that I had drastically changed the classes in my code: the old pickles wouldn't come close to loading. Instead of trying to write special faked out classes on a class-by-class basis for my old objects, which would instantiate the new objects with the appropriate data, I decided to take a simpler, more central approach.




The following code loads arbitrary pickles (well, there are probably some that it won't load, like ones which have object states which aren't dicts). It just loads their data into totally inert objects which you can then traverse and do what you like to. It's pretty similar to processing a DOM tree. So I'm going to use this to traverse my pickle and write out the new-style XML.




import sys, pickle

# need a subclass so __dict__ is available
class FakeThing(object):
pass

class PickleUpgrader(pickle.Unpickler):
def find_class(self, module, cname):
# Pickle tries to load a couple things like copy_reg and
# __builtin__.object even though a pickle file doesn't
# explicitly reference them (afaict): allow them to be loaded
# normally.
if module in ('copy_reg', '__builtin__'):
thing = pickle.Unpickler.find_class(self, module, cname)
return thing
return FakeThing

root = PickleUpgrader(open(sys.argv[1])).load()

# Do whatever to 'root' here.