diff --git a/src/body.cpp b/src/body.cpp
index 4b9b3ce..15fbf71 100644
--- a/src/body.cpp
+++ b/src/body.cpp
@@ -1,6 +1,12 @@
 #include "libs.h"
 #include "body.h"
 #include "frame.h"
+#include "serializer.h"
+#include "star.h"
+#include "planet.h"
+#include "space_station.h"
+#include "ship.h"
+#include "player.h"
 
 Body::Body(void) {
   m_frame = 0;
@@ -15,9 +21,74 @@ Body::~Body(void) {
   assert(m_dead);
 }
 
-void Body::Serialize(void) { }
+void Body::Save(void) {
+  using namespace Serializer::Write;
+  wr_int(Serializer::LookupFrame(m_frame));
+  wr_string(m_label);
+  wr_bool(m_onscreen);
+  wr_vector3d(m_projectedPos);
+  wr_bool(m_dead);
+}
 
-Body* Body::Unserialize(void) { }
+void Body::Load(void) {
+  using namespace Serializer::Read;
+  m_frame         = Serializer::LookupFrame(rd_int());
+  m_label         = rd_string();
+  m_onscreen      = rd_bool();
+  m_projectedPos  = rd_vector3d();
+  m_dead          = rd_bool();
+}
+
+void Body::Serialize(void) {
+  using namespace Serializer::Write;
+  wr_int((int)GetType());
+  switch(GetType()) {
+    case Object::STAR:
+    case Object::PLANET:
+    case Object::SPACESTATION:
+    case Object::SHIP:
+    case Object::PLAYER:
+      Save();
+      break;
+    default:
+      assert(0);
+  }
+  wr_vector3d(GetPosition());
+  matrix4x4d m;
+  GetRotMatrix(m);
+  for(int i = 0; i < 16; i++) wr_double(m[i]);
+}
+
+Body* Body::Unserialize(void) {
+  Body* b = 0;
+  using namespace Serializer::Read;
+  Object::Type type = (Object::Type)rd_int();
+  switch(type) {
+    case Object::STAR:
+      b = new Star(); break;
+    case Object::PLANET:
+      b = new Planet(); break;
+    case Object::SPACESTATION:
+      b = new SpaceStation(); break;
+    case Object::SHIP:
+      b = new Ship(); break;
+    case Object::PLAYER:
+      b = new Player(); break;
+    default:
+      /* TODO: should assert. */
+      return 0;
+  }
+  b->Load();
+  /* Must SetFrame() correctly so ModelBodies can add geom to space. */
+  Frame* f = b->m_frame;
+  b->m_frame = 0;
+  b->SetFrame(f);
+  b->SetPosition(rd_vector3d());
+  matrix4x4d m;
+  for(int i = 0; i < 16; i++) m[i] = rd_double();
+  b->SetRotMatrix(m);
+  return b;
+}
 
 /* f == NULL, then absolute position within system. */
 vector3d Body::GetPositionRelTo(const Frame* relTo) {
diff --git a/src/body.h b/src/body.h
index 186c43a..8263649 100644
--- a/src/body.h
+++ b/src/body.h
@@ -15,6 +15,7 @@ public:
   virtual ~Body(void);
   void Serialize(void);
   static Body* Unserialize(void);
+  virtual void PostLoadFixup(void) { };
   virtual void SetPosition(vector3d p) = 0;
   virtual vector3d GetPosition(void) const = 0; /* Within frame. */
   virtual void SetVelocity(vector3d v) { assert(0); }
@@ -49,6 +50,8 @@ public:
   enum { FLAG_CAN_MOVE_FRAME = 1 };
 
 protected:
+  virtual void Save(void);
+  virtual void Load(void);
   unsigned int m_flags;
 
 private:
diff --git a/src/dynamic_body.cpp b/src/dynamic_body.cpp
index 13b50f8..0340d84 100644
--- a/src/dynamic_body.cpp
+++ b/src/dynamic_body.cpp
@@ -2,6 +2,7 @@
 #include "dynamic_body.h"
 #include "space.h"
 #include "frame.h"
+#include "serializer.h"
 
 DynamicBody::DynamicBody(void) : ModelBody() {
   m_flags = Body::FLAG_CAN_MOVE_FRAME;
@@ -12,6 +13,16 @@ DynamicBody::DynamicBody(void) : ModelBody() {
   dBodySetMass(m_body, &m_mass);
 }
 
+void DynamicBody::Save(void) {
+  using namespace Serializer::Write;
+  ModelBody::Save();
+}
+
+void DynamicBody::Load(void) {
+  using namespace Serializer::Read;
+  ModelBody::Load();
+}
+
 void DynamicBody::Enable(void) {
   ModelBody::Enable();
   dBodyEnable(m_body);
diff --git a/src/dynamic_body.h b/src/dynamic_body.h
index d37f9e3..769151b 100644
--- a/src/dynamic_body.h
+++ b/src/dynamic_body.h
@@ -29,6 +29,8 @@ public:
   dMass   m_mass;
 
 protected:
+  virtual void Save(void);
+  virtual void Load(void);
 
 private:
   ObjMesh* m_mesh;
diff --git a/src/frame.cpp b/src/frame.cpp
index 1596588..93b8643 100644
--- a/src/frame.cpp
+++ b/src/frame.cpp
@@ -23,6 +23,8 @@ void Frame::Serialize(Frame* f) {
   wr_vector3d(f->m_angVel);
   wr_vector3d(f->m_pos);
 
+  wr_int(Serializer::LookupSystemBody(f->m_sbody));
+  wr_int(Serializer::LookupBody(f->m_astroBody));
   wr_int(f->m_children.size());
   for(std::list<Frame*>::iterator i = f->m_children.begin();
       i != f->m_children.end(); ++i) {
@@ -39,7 +41,9 @@ Frame* Frame::Unserialize(Frame* parent) {
   f->m_label  = rd_string();
   for(int i = 0; i < 16; i++) f->m_orient[i] = rd_double();
   f->m_angVel = rd_vector3d();
-  printf("Frame rad %f, called %s\n", f->m_radius, f->m_label.c_str());
+  f->m_sbody = Serializer::LookupSystemBody(rd_int());
+  f->m_astroBody = (Body*)rd_int();
+  f->m_vel = vector3d(0.0);
   for(int i = rd_int(); i > 0; --i) {
     f->m_children.push_back(Unserialize(f));
   }
@@ -47,6 +51,14 @@ Frame* Frame::Unserialize(Frame* parent) {
   return f;
 }
 
+void Frame::PostUnserializeFixup(Frame* f) {
+  f->m_astroBody = Serializer::LookupBody((size_t)f->m_astroBody);
+  for(std::list<Frame*>::iterator i = f->m_children.begin();
+      i != f->m_children.end(); ++i) {
+    PostUnserializeFixup(*i);
+  }
+}
+
 void Frame::RemoveChild(Frame* f) {
   m_children.remove(f);
 }
diff --git a/src/frame.h b/src/frame.h
index 6b28f4b..a8af465 100644
--- a/src/frame.h
+++ b/src/frame.h
@@ -15,6 +15,7 @@ public:
   ~Frame(void);
 
   static void Serialize(Frame*);
+  static void PostUnserializeFixup(Frame* f);
   static Frame* Unserialize(Frame* parent);
 
   const char* GetLabel(void) const              { return m_label.c_str(); }
diff --git a/src/main.cpp b/src/main.cpp
index 52fcf32..db0e207 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -462,6 +462,13 @@ void L3D::Unserialize(void) {
   selectedSystem = StarSystem::Unserialize();
   gameTime = rd_double();
   currentSystem = StarSystem::Unserialize();
+  Space::Clear();
+  if(L3D::player) {
+    L3D::player->MarkDead();
+    Space::bodies.remove(L3D::player);
+    delete L3D::player;
+    L3D::player = 0;
+  }
   Space::Unserialize();
 }
 
diff --git a/src/model_body.cpp b/src/model_body.cpp
index b11a273..d90d8f7 100644
--- a/src/model_body.cpp
+++ b/src/model_body.cpp
@@ -6,6 +6,7 @@
 #include "l3d.h"
 #include "world_view.h"
 #include "model_coll_mesh_data.h"
+#include "serializer.h"
 
 ModelBody::ModelBody(void): Body() {
   m_triMeshLastMatrixIndex = 0;
@@ -19,6 +20,16 @@ ModelBody::~ModelBody(void) {
   }
 }
 
+void ModelBody::Save(void) {
+  using namespace Serializer::Write;
+  Body::Save();
+}
+
+void ModelBody::Load(void) {
+  using namespace Serializer::Read;
+  Body::Load();
+}
+
 void ModelBody::Disable(void) {
   for(unsigned int i = 0; i < geoms.size(); i++) {
     dGeomDisable(geoms[i]);
diff --git a/src/model_body.h b/src/model_body.h
index b017d5b..0f7fd99 100644
--- a/src/model_body.h
+++ b/src/model_body.h
@@ -39,6 +39,8 @@ public:
     int flags;
   };
 protected:
+  virtual void Save(void);
+  virtual void Load(void);
   std::vector<Geom> geomColl;
 private:
   CollMeshSet* m_collMeshSet;
diff --git a/src/planet.cpp b/src/planet.cpp
index e080536..e69df55 100644
--- a/src/planet.cpp
+++ b/src/planet.cpp
@@ -3,22 +3,44 @@
 #include "frame.h"
 #include "l3d.h"
 #include "world_view.h"
+#include "serializer.h"
 
 Planet::Planet(StarSystem::SBody* sbody) : Body() {
   pos     = vector3d(0, 0, 0);
+  this->sbody = sbody;
+  Init();
+}
+
+void Planet::Init(void) {
   geom    = dCreateSphere(0, sbody->GetRadius());
   dGeomSetData(geom, static_cast<Body*>(this));
   m_mass = sbody->GetMass();
-  this->sbody = *sbody;
-  this->sbody.children.clear();
-  this->sbody.parent = 0;
   crudDList = 0;
 }
 
+void Planet::Save(void) {
+  using namespace Serializer::Write;
+  Body::Save();
+  wr_vector3d(pos);
+  wr_int(Serializer::LookupSystemBody(sbody));
+}
+
+void Planet::Load(void) {
+  using namespace Serializer::Read;
+  Body::Load();
+  pos = rd_vector3d();
+  sbody = Serializer::LookupSystemBody(rd_int());
+  Init();
+}
+
 Planet::~Planet(void) {
   dGeomDestroy(geom);
 }
 
+double Planet::GetRadius(void) const {
+  return sbody->GetRadius();
+}
+
 vector3d Planet::GetPosition(void) const {
   return pos;
 }
@@ -592,7 +614,7 @@ void Planet::DrawRockyPlanet(void) {
   matrix4x4d rot;
   float col[4], col2[4];
   //MTRand rng((int)L3D::GetGameTime());
-  MTRand rng(sbody.seed);
+  MTRand rng(sbody->seed);
   float darkblue[4] = { .05, .05, .2, 1 };
   float blue[4]   = { .2, .2, 1, 1 };
   float green[4]  = { .2, .8, .2, 1 };
@@ -601,7 +623,7 @@ void Planet::DrawRockyPlanet(void) {
   ColRangeObj_t barrenContCol         = { { .2, .2, .2, 1 }, { 0, 0, 0, 0 }, .3 };
   ColRangeObj_t barrenEjectaCraterCol = { { .5, .5, .5, 1 }, { 0, 0, 0, 0 }, .2 };
 
-  switch(sbody.type) {
+  switch(sbody->type) {
   case StarSystem::TYPE_PLANET_DWARF:
   case StarSystem::TYPE_PLANET_SMALL:
     barrenBodyCol.GenCol(col2, rng);
@@ -695,7 +717,7 @@ void Planet::DrawRockyPlanet(void) {
 
 void Planet::DrawGasGiant(void) {
   //MTRand rng((int)L3D::GetGameTime());
-  MTRand rng(sbody.seed+9);
+  MTRand rng(sbody->seed+9);
   float col[4];
 
   /* Just use a random gas giant flavour for the moment. */
@@ -790,39 +812,39 @@ static void _DrawAtmosphere(double rad1, double rad2, vector3d& pos, const float
 }
 
 void Planet::DrawAtmosphere(double rad, vector3d& pos) {
-  if(sbody.type == StarSystem::TYPE_PLANET_SMALL) {
+  if(sbody->type == StarSystem::TYPE_PLANET_SMALL) {
     const float c[4] = { .2, .2, .3, .8 };
     _DrawAtmosphere(rad*0.99, rad*1.05, pos, c);
   }
-  else if(sbody.type == StarSystem::TYPE_PLANET_CO2_THICK_ATMOS) {
+  else if(sbody->type == StarSystem::TYPE_PLANET_CO2_THICK_ATMOS) {
     const float c[4] = { .8, .8, .8, .8 };
     _DrawAtmosphere(rad*0.99, rad*1.1, pos, c);
   }
-  else if(sbody.type == StarSystem::TYPE_PLANET_CO2) {
+  else if(sbody->type == StarSystem::TYPE_PLANET_CO2) {
     const float c[4] = { .5, .5, .5, .8 };
     _DrawAtmosphere(rad*0.99, rad*1.05, pos, c);
   }
-  else if(sbody.type == StarSystem::TYPE_PLANET_METHANE_THICK_ATMOS) {
+  else if(sbody->type == StarSystem::TYPE_PLANET_METHANE_THICK_ATMOS) {
     const float c[4] = { .2, .6, .3, .8 };
     _DrawAtmosphere(rad*0.99, rad*1.1, pos, c);
   }
-  else if(sbody.type == StarSystem::TYPE_PLANET_METHANE) {
+  else if(sbody->type == StarSystem::TYPE_PLANET_METHANE) {
     const float c[4] = { .2, .6, .3, .8 };
     _DrawAtmosphere(rad*0.99, rad*1.05, pos, c);
   }
-  else if(sbody.type == StarSystem::TYPE_PLANET_HIGHLY_VOLCANIC) {
+  else if(sbody->type == StarSystem::TYPE_PLANET_HIGHLY_VOLCANIC) {
     const float c[4] = { .5, .2, .2, .8 };
     _DrawAtmosphere(rad*0.99, rad*1.05, pos, c);
   }
-  else if(sbody.type == StarSystem::TYPE_PLANET_WATER_THICK_ATMOS) {
+  else if(sbody->type == StarSystem::TYPE_PLANET_WATER_THICK_ATMOS) {
     const float c[4] = { .8, .8, .8, .8 };
     _DrawAtmosphere(rad*0.99, rad*1.1, pos, c);
   }
-  else if(sbody.type == StarSystem::TYPE_PLANET_WATER) {
+  else if(sbody->type == StarSystem::TYPE_PLANET_WATER) {
     const float c[4] = { .2, .2, .4, .8 };
     _DrawAtmosphere(rad*0.99, rad*1.05, pos, c);
   }
-  else if(sbody.type == StarSystem::TYPE_PLANET_INDIGENOUS_LIFE) {
+  else if(sbody->type == StarSystem::TYPE_PLANET_INDIGENOUS_LIFE) {
     const float c[4] = { .2, .2, .5, .8 };
     _DrawAtmosphere(rad*0.99, rad*1.05, pos, c);
   }
@@ -831,7 +853,7 @@ void Planet::DrawAtmosphere(double rad, vector3d& pos) {
 void Planet::Render(const Frame* a_camFrame) {
   glPushMatrix();
 
-  double rad = sbody.GetRadius();
+  double rad = sbody->GetRadius();
   matrix4x4d ftran;
   Frame::GetFrameTransform(GetFrame(), a_camFrame, ftran);
   vector3d fpos = ftran * GetPosition();
@@ -867,7 +889,7 @@ void Planet::Render(const Frame* a_camFrame) {
       crudDList = glGenLists(1);
       glNewList(crudDList, GL_COMPILE);
       /* This is a rather brittle test.. */
-      if(sbody.type < StarSystem::TYPE_PLANET_DWARF) {
+      if(sbody->type < StarSystem::TYPE_PLANET_DWARF) {
         DrawGasGiant();
       } else {
         DrawRockyPlanet();
diff --git a/src/planet.h b/src/planet.h
index 323097a..1fba988 100644
--- a/src/planet.h
+++ b/src/planet.h
@@ -7,16 +7,23 @@ class Planet : public Body {
 public:
   OBJDEF(Planet, Body, PLANET);
   Planet(StarSystem::SBody*);
+  Planet(void) { };
   virtual ~Planet(void);
   virtual void SetPosition(vector3d p);
   virtual vector3d GetPosition(void) const;
   void SetRadius(double radius);
-  virtual double GetRadius(void) const { return sbody.GetRadius(); }
+  virtual double GetRadius(void) const;
   virtual void Render(const Frame* camFrame);
   virtual void SetFrame(Frame* f);
   virtual bool OnCollision(Body* b, Uint32 flags) { return true; }
   virtual double GetMass(void) const { return m_mass; }
+
+protected:
+  virtual void Save(void);
+  virtual void Load(void);
+
 private:
+  void Init(void);
   void DrawRockyPlanet(void);
   void DrawGasGiant(void);
   void DrawAtmosphere(double rad, vector3d& pos);
@@ -24,7 +31,7 @@ private:
   double m_mass;
   vector3d pos;
   dGeomID geom;
-  StarSystem::SBody sbody;
+  StarSystem::SBody* sbody;
   GLuint crudDList;
 };
 
diff --git a/src/player.h b/src/player.h
index 979c8da..a180a84 100644
--- a/src/player.h
+++ b/src/player.h
@@ -6,6 +6,7 @@ class Player : public Ship {
 public:
   OBJDEF(Player, Ship, PLAYER);
   Player(ShipType::Type shipType);
+  Player(void) { }
   virtual ~Player(void);
   void PollControls(void);
   virtual void Render(const Frame* camFrame);
diff --git a/src/serializer.cpp b/src/serializer.cpp
index 4ae6976..8020a2a 100644
--- a/src/serializer.cpp
+++ b/src/serializer.cpp
@@ -10,11 +10,11 @@ static std::vector<Frame*> g_frames;
 static std::vector<Body*>g_bodies;
 static std::vector<StarSystem::SBody*>g_sbodies;
 
-Frame* LookupFrame(int index) {
+Frame* LookupFrame(size_t index) {
   return g_frames[index];
 }
 
-int LoopupFrame(Frame* f) {
+int LookupFrame(Frame* f) {
   for(unsigned int i = 0; i < g_frames.size(); i++) {
     if(g_frames[i] == f) return i;
   }
@@ -34,7 +34,7 @@ void IndexFrames(void) {
   AddFrame(Space::rootFrame);
 }
 
-StarSystem::SBody* LookupSystemBody(int index) { return (index == -1 ? 0 : g_sbodies[index]); }
+StarSystem::SBody* LookupSystemBody(size_t index) { return (index == ~(size_t)0 ? 0 : g_sbodies[index]); }
 int LookupSystemBody(StarSystem::SBody* b) {
   if(!b) return -1;
   for(unsigned int i = 0; i < g_sbodies.size(); i++) {
@@ -55,7 +55,7 @@ void IndexSystemBodies(StarSystem* s) {
   add_sbody(s->rootBody);
 }
 
-Body* LookupBody(int index) { return (index == -1 ? 0 : g_bodies[index]); }
+Body* LookupBody(size_t index) { return (index == ~(size_t)0 ? 0 : g_bodies[index]); }
 int LookupBody(Body* b) {
   if(!b) return -1;
   for(unsigned int i = 0; i < g_bodies.size(); i++) {
diff --git a/src/serializer.h b/src/serializer.h
index 687ab65..4353355 100644
--- a/src/serializer.h
+++ b/src/serializer.h
@@ -11,15 +11,15 @@ class StarSystem::SBody;
 
 namespace Serializer {
   void IndexFrames(void);
-  Frame* LookupFrame(Frame* f);
+  Frame* LookupFrame(size_t index);
+  int LookupFrame(Frame* f);
 
   void IndexBodies(void);
-  Body* LookupBody(int index);
-  int LookupSystemBody(StarSystem::SBody*);
+  Body* LookupBody(size_t index);
   int LookupBody(Body*);
 
   void IndexSystemBodies(StarSystem*);
-  StarSystem::SBody* LookupSystemBody(int index);
+  StarSystem::SBody* LookupSystemBody(size_t index);
   int LookupSystemBody(StarSystem::SBody*);
 
   namespace Write {
diff --git a/src/ship.cpp b/src/ship.cpp
index 484bf15..da0ab15 100644
--- a/src/ship.cpp
+++ b/src/ship.cpp
@@ -5,6 +5,7 @@
 #include "space.h"
 #include "model_coll_mesh_data.h"
 #include "space_station.h"
+#include "serializer.h"
 
 static ObjParams params = {
   { 0.5, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
@@ -22,6 +23,70 @@ static ObjParams params = {
   { "IR-L33T", "ME TOO" },
 };
 
+void Ship::Save(void) {
+  using namespace Serializer::Write;
+  DynamicBody::Save();
+  wr_int(Serializer::LookupBody(m_combatTarget));
+  wr_int(Serializer::LookupBody(m_navTarget));
+  wr_float(m_dockingTimer);
+  wr_float(m_angThrusters[0]);
+  wr_float(m_angThrusters[1]);
+  wr_float(m_angThrusters[2]);
+  for(int i = 0; i < ShipType::THRUSTER_MAX; i++) wr_float(m_thrusters[i]);
+  wr_float(m_wheelTransition);
+  wr_float(m_wheelState);
+  wr_float(m_launchLockTimeout);
+  wr_bool(m_testLanded);
+  wr_int((int)m_flightState);
+  for(int i = 0; i < ShipType::GUNMOUNT_MAX; i++) wr_int(m_gunState[i]);
+  wr_int((int)m_shipType);
+  wr_int(m_dockedWithPort);
+  wr_int(Serializer::LookupBody(m_dockedWith));
+  printf("TODO: NOT SAVING SHIP EQUIPMENT YET!!\n");
+}
+
+void Ship::Load(void) {
+  using namespace Serializer::Read;
+  DynamicBody::Load();
+  /* Needs some fixing. */
+  m_combatTarget = (Body*)rd_int();
+  m_navTarget = (Body*)rd_int();
+  m_dockingTimer = rd_float();
+  m_angThrusters[0] = rd_float();
+  m_angThrusters[1] = rd_float();
+  m_angThrusters[2] = rd_float();
+  for(int i = 0; i < ShipType::THRUSTER_MAX; i++) m_thrusters[i] = rd_float();
+  m_wheelTransition = rd_float();
+  m_wheelState = rd_float();
+  m_launchLockTimeout = rd_float();
+  m_testLanded = rd_bool();
+  m_flightState = (FlightState) rd_int();
+  for(int i = 0; i < ShipType::GUNMOUNT_MAX; i++) {
+    m_gunState[i] = rd_int();
+    m_tempLaserGeom[i] = 0;
+  }
+  m_shipType = (ShipType::Type)rd_int();
+  m_dockedWithPort = rd_int();
+  m_dockedWith = (SpaceStation*)rd_int();
+  /* TODO: */
+  m_equipment = EquipSet(m_shipType);
+  Init();
+}
+
+void Ship::Init(void) {
+  const ShipType& stype = GetShipType();
+  SetModel(stype.sbreModel);
+  SetMassDistributionFromCollMesh(GetModelSBRECollMesh(stype.sbreModel));
+  GeomsSetBody(m_body);
+  UpdateMass();
+}
+
+void Ship::PostLoadFixup(void) {
+  m_combatTarget = Serializer::LookupBody((size_t)m_combatTarget);
+  m_navTarget = Serializer::LookupBody((size_t)m_navTarget);
+  m_dockedWith = (SpaceStation*)Serializer::LookupBody((size_t)m_dockedWith);
+}
+
 Ship::Ship(ShipType::Type shipType) : DynamicBody() {
   m_flightState       = FLYING;
   m_testLanded        = false;
@@ -42,11 +107,8 @@ Ship::Ship(ShipType::Type shipType) : DynamicBody() {
     m_gunState[i] = 0;
   }
   memset(m_thrusters, 0, sizeof(m_thrusters)); 
-  const ShipType& stype = GetShipType();
-  SetModel(stype.sbreModel);
-  SetMassDistributionFromCollMesh(GetModelSBRECollMesh(stype.sbreModel));
-  GeomsSetBody(m_body);
-  UpdateMass();
+
+  Init();
 }
 
 void Ship::UpdateMass(void) {
diff --git a/src/ship.h b/src/ship.h
index 8f11a8c..1701953 100644
--- a/src/ship.h
+++ b/src/ship.h
@@ -18,6 +18,7 @@ class Ship : public DynamicBody {
 public:
   OBJDEF(Ship, DynamicBody, SHIP);
   Ship(ShipType::Type shipType);
+  Ship(void) { }
   virtual void SetDockedWith(SpaceStation*, int port);
   SpaceStation* GetDockedWith(void) { return m_dockedWith; }
   void SetNavTarget(Body* const target);
@@ -51,7 +52,11 @@ public:
   };
 
   EquipSet m_equipment;
+
+  virtual void PostLoadFixup(void);
 protected:
+  virtual void Save(void);
+  virtual void Load(void);
   void RenderLaserfire(void);
   
   SpaceStation* m_dockedWith;
@@ -59,6 +64,7 @@ protected:
   enum ShipType::Type m_shipType;
   Uint32 m_gunState[ShipType::GUNMOUNT_MAX];
 private:
+  void Init(void);
   bool IsFiringLasers(void);
   void TestLanded(void);
 
diff --git a/src/space.cpp b/src/space.cpp
index ebafa6d..b05c759 100644
--- a/src/space.cpp
+++ b/src/space.cpp
@@ -30,21 +30,36 @@ void Space::Init(void) {
 void Space::Serialize(void) {
   using namespace Serializer::Write;
   Serializer::IndexFrames();
+  Serializer::IndexBodies();
+  Serializer::IndexSystemBodies(L3D::currentSystem);
+  Frame::Serialize(rootFrame);
   printf("%d bodies to write\n", bodies.size());
   wr_int(bodies.size());
   for(bodiesIter_t i = bodies.begin(); i != bodies.end(); ++i) {
+    printf("Serializing %s\n", (*i)->GetLabel().c_str());
     (*i)->Serialize();
   }
 }
 
 void Space::Unserialize(void) {
   using namespace Serializer::Read;
+  Serializer::IndexSystemBodies(L3D::currentSystem);
+  rootFrame = Frame::Unserialize(0);
   Serializer::IndexFrames();
   int num_bodies = rd_int();
   printf("%d bodies to read\n", num_bodies);
   for(int i = 0; i < num_bodies; i++) {
-    bodies.push_back(Body::Unserialize());
+    Body* b = Body::Unserialize();
+    if(b) bodies.push_back(b);
+    if(b->IsType(Object::PLAYER)) L3D::player = (Player*)b;
   }
+  printf("%d bodies read\n", bodies.size());
+  /* Bodies with references to others must fix these up. */
+  Serializer::IndexBodies();
+  for(bodiesIter_t i = bodies.begin(); i != bodies.end(); ++i) {
+    (*i)->PostLoadFixup();
+  }
+  Frame::PostUnserializeFixup(rootFrame);
 }
 
 void Space::Clear(void) {
diff --git a/src/space_station.cpp b/src/space_station.cpp
index 32f4cb7..8bd707b 100644
--- a/src/space_station.cpp
+++ b/src/space_station.cpp
@@ -2,6 +2,8 @@
 #include "ship.h"
 #include "model_coll_mesh_data.h"
 #include "gameconsts.h"
+#include "star_system.h"
+#include "serializer.h"
 
 struct SpaceStationType {
   Uint32 sbreModel;
@@ -13,6 +15,20 @@ struct SpaceStationType stationTypes[SpaceStation::TYPE_MAX] = {
   { 90, SpaceStationType::SURFACE },
 };
 
+void SpaceStation::Save(void) {
+  using namespace Serializer::Write;
+  ModelBody::Save();
+  wr_int((int)m_type);
+}
+
+void SpaceStation::Load(void) {
+  using namespace Serializer::Read;
+  ModelBody::Load();
+  m_type = (TYPE)rd_int();
+  m_numPorts = 0;
+  Init();
+}
+
 static ObjParams params = {
   { 0.5, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
   { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
@@ -71,9 +87,13 @@ void SpaceStation::GetDockingSurface(CollMeshSet* mset, int midx) {
 }
 
 SpaceStation::SpaceStation(TYPE type) : ModelBody() {
-  const Uint32 sbreModel = stationTypes[type].sbreModel;
   m_type = type;
   m_numPorts = 0;
+  Init();
+}
+
+void SpaceStation::Init(void) {
+  const Uint32 sbreModel = stationTypes[m_type].sbreModel;
   SetModel(sbreModel);
 
   CollMeshSet* mset = GetModelCollMeshSet(sbreModel);
@@ -81,14 +101,6 @@ SpaceStation::SpaceStation(TYPE type) : ModelBody() {
     if(geomColl[i].flags & 0x10) {
       /* Docking surface. */
       GetDockingSurface(mset, i);
-      //mset->meshInfo[i];
-#if 0
-      struct meshinfo_t {
-        int flags;
-        int triStart; /* Into triIndices. */
-        int numTris;
-      };
-#endif
     }
   }
 }
diff --git a/src/space_station.h b/src/space_station.h
index 2bae074..0747ba0 100644
--- a/src/space_station.h
+++ b/src/space_station.h
@@ -12,6 +12,7 @@ public:
   OBJDEF(SpaceStation, ModelBody, SPACESTATION);
   enum TYPE { JJHOOP, GROUND_FLAVOURED, TYPE_MAX };
   SpaceStation(TYPE);
+  SpaceStation(void) { }
   virtual ~SpaceStation(void);
   virtual bool OnCollision(Body* b, Uint32 flags);
   virtual void Render(const Frame* camFrame);
@@ -26,7 +27,12 @@ public:
     vector3d horiz;
   } port[MAX_DOCKING_PORTS];
 
+protected:
+  virtual void Save(void);
+  virtual void Load(void);
+
 private:
+  void Init(void);
   TYPE m_type;
   int m_numPorts;
 };
diff --git a/src/star.cpp b/src/star.cpp
index 9b729b2..0fcb89e 100644
--- a/src/star.cpp
+++ b/src/star.cpp
@@ -1,6 +1,7 @@
 #include "libs.h"
 #include "star.h"
 #include "l3d.h"
+#include "serializer.h"
 
 Star::Star(StarSystem::SBody* sbody): Body() {
   this->type = sbody->type;
@@ -17,6 +18,24 @@ void Star::SetPosition(vector3d p) {
   pos = p;
 }
 
+void Star::Save(void) {
+  using namespace Serializer::Write;
+  Body::Save();
+  wr_int(type);
+  wr_vector3d(pos);
+  wr_double(radius);
+  wr_double(mass);
+}
+
+void Star::Load(void) {
+  using namespace Serializer::Read;
+  Body::Load();
+  type = (StarSystem::BodyType)rd_int();
+  pos = rd_vector3d();
+  radius = rd_double();
+  mass = rd_double();
+}
+
 void Star::Render(const Frame* a_camFrame) {
   glDisable(GL_LIGHTING);
   glDisable(GL_DEPTH_TEST);
diff --git a/src/star.h b/src/star.h
index a4149fb..7614a8f 100644
--- a/src/star.h
+++ b/src/star.h
@@ -8,6 +8,7 @@ class Star: public Body {
 public:
   OBJDEF(Star, Body, STAR);
   Star(StarSystem::SBody* sbody);
+  Star(void) { }
   virtual ~Star(void) { };
   virtual void SetPosition(vector3d p);
   virtual vector3d GetPosition(void) const;
@@ -15,6 +16,10 @@ public:
   virtual void Render(const Frame* camFrame);
   virtual double GetMass(void) const { return mass; }
 
+protected:
+  virtual void Save(void);
+  virtual void Load(void);
+
 private:
   StarSystem::BodyType type;
   vector3d pos;