From 6251814604a2395d66dc28fbe0cde8ce99e7be2c Mon Sep 17 00:00:00 2001
From: James Turner <zakalawe@mac.com>
Date: Mon, 18 Oct 2010 00:58:35 +0100
Subject: [PATCH] Use a property listener on the root, to observe property
 creation, and thus lazily update the MP property map. Fixes bug 164, and
 probably many latent MP missing-property issues.

---
 src/Network/multiplay.cxx | 65 +++++++++++++++++++++++++++++++--------
 src/Network/multiplay.hxx |  8 +++++
 2 files changed, 61 insertions(+), 12 deletions(-)

diff --git a/src/Network/multiplay.cxx b/src/Network/multiplay.cxx
index eb8a52c08..e7991e6b8 100644
--- a/src/Network/multiplay.cxx
+++ b/src/Network/multiplay.cxx
@@ -49,6 +49,24 @@ using std::string;
 const char sFG_MULTIPLAY_BID[] = "$Id$";
 const char sFG_MULTIPLAY_HID[] = FG_MULTIPLAY_HID;
 
+typedef std::set<std::string> string_set;
+
+class MPPropertyListener : public SGPropertyChangeListener
+{
+public:
+  MPPropertyListener(FGMultiplay* mp) :
+    _multiplay(mp)
+  {
+  }
+
+  virtual void childAdded(SGPropertyNode*, SGPropertyNode*)
+  {
+    _multiplay->setPropertiesChanged();
+  }
+
+private:
+  FGMultiplay* _multiplay;
+};
 
 /******************************************************************
 * Name: FGMultiplay
@@ -73,6 +91,7 @@ FGMultiplay::FGMultiplay (const string &dir, const int rate, const string &host,
 
   }
 
+  mPropertiesChanged = true;
 }
 
 
@@ -97,19 +116,38 @@ bool FGMultiplay::open() {
     }
 
     set_enabled(true);
-
-    SGPropertyNode* root = globals->get_props();
-
-    /// Build up the id to property map
     
-    for (unsigned i = 0; i < FGMultiplayMgr::numProperties; ++i) {
+    mPropertiesChanged = true;
+    
+    MPPropertyListener* pl = new MPPropertyListener(this);
+    globals->get_props()->addChangeListener(pl, false);
+    return is_enabled();
+}
+
+void FGMultiplay::findProperties()
+{
+  if (!mPropertiesChanged) {
+    return;
+  }
+  
+  mPropertiesChanged = false;
+  
+  for (unsigned i = 0; i < FGMultiplayMgr::numProperties; ++i) {
       const char* name = FGMultiplayMgr::sIdPropertyList[i].name;
-      SGPropertyNode* pNode = root->getNode(name);
-      if (pNode)
-        mPropertyMap[FGMultiplayMgr::sIdPropertyList[i].id] = pNode;
+      SGPropertyNode* pNode = globals->get_props()->getNode(name);
+      if (!pNode) {
+        continue;
+      }
+      
+      int id = FGMultiplayMgr::sIdPropertyList[i].id;
+      if (mPropertyMap.find(id) != mPropertyMap.end()) {
+        continue; // already activated
+      }
+      
+      mPropertyMap[id] = pNode;
+      SG_LOG(SG_NETWORK, SG_INFO, "activating MP property:" << pNode->getPath());
     }
 
-    return is_enabled();
 }
 
 
@@ -121,7 +159,8 @@ bool FGMultiplay::open() {
 bool FGMultiplay::process() {
   using namespace simgear;
   if (get_direction() == SG_IO_OUT) {
-
+    findProperties();
+    
     // check if we have left initialization phase. That will not provide
     // interresting data, also the freeze in simulation time hurts the
     // multiplayer clients
@@ -270,8 +309,10 @@ bool FGMultiplay::process() {
 * Description:  Closes the multiplayer mgrs to stop any further
 * network processing
 ******************************************************************/
-bool FGMultiplay::close() {
-
+bool FGMultiplay::close()
+{
+  mPropertyMap.clear();
+  
   FGMultiplayMgr* mgr = (FGMultiplayMgr*) globals->get_subsystem("mp");
 
   if (mgr == 0) {
diff --git a/src/Network/multiplay.hxx b/src/Network/multiplay.hxx
index 0d5563c0e..f596ea0eb 100644
--- a/src/Network/multiplay.hxx
+++ b/src/Network/multiplay.hxx
@@ -78,7 +78,15 @@ public:
     */
     bool close();
 
+    void setPropertiesChanged()
+    {
+      mPropertiesChanged = true;
+    }
 private:
+  bool mPropertiesChanged;
+  
+  void findProperties();
+  
   // Map between the property id's from the multiplayers network packets
   // and the property nodes
   typedef std::map<unsigned, SGSharedPtr<SGPropertyNode> > PropertyMap;