Index: code/trunk/src/orxonox/Level.cc
===================================================================
--- code/trunk/src/orxonox/Level.cc	(revision 9667)
+++ code/trunk/src/orxonox/Level.cc	(revision 10624)
@@ -35,4 +35,5 @@
 #include "core/XMLFile.h"
 #include "core/XMLPort.h"
+#include "core/module/PluginReference.h"
 
 #include "infos/PlayerInfo.h"
@@ -49,4 +50,5 @@
         RegisterObject(Level);
 
+        this->setLevel(WeakPtr<Level>(this)); // store a weak-pointer to itself (a strong-pointer would create a recursive dependency)
 
         this->registerVariables();
@@ -63,5 +65,7 @@
 
             if (this->xmlfile_)
-                Loader::unload(this->xmlfile_);
+                Loader::getInstance().unload(this->xmlfile_);
+
+            this->unloadPlugins();
         }
     }
@@ -71,4 +75,5 @@
         SUPER(Level, XMLPort, xmlelement, mode);
 
+        XMLPortParam(Level, "plugins",  setPluginsString,  getPluginsString,  xmlelement, mode);
         XMLPortParam(Level, "gametype", setGametypeString, getGametypeString, xmlelement, mode).defaultValues("Gametype");
 
@@ -95,5 +100,5 @@
         this->xmlfile_ = new XMLFile(mask, this->xmlfilename_);
 
-        Loader::open(this->xmlfile_);
+        Loader::getInstance().load(this->xmlfile_);
     }
 
@@ -105,4 +110,31 @@
             Template::getTemplate(*it)->applyOn(this);
         }
+    }
+
+    void Level::setPluginsString(const std::string& pluginsString)
+    {
+        // unload old plugins
+        this->unloadPlugins();
+
+        // load new plugins
+        this->pluginsString_ = pluginsString;
+        SubString tokens(pluginsString, ",");
+        for (size_t i = 0; i < tokens.size(); ++i)
+            this->plugins_.push_back(new PluginReference(tokens[i]));
+    }
+
+    void Level::unloadPlugins()
+    {
+        // use destroyLater() - this ensures that plugins are not unloaded too early.
+        // Note: When a level gets unloaded, the Level object is usually the last object that gets destroyed. This is because all other
+        //       objects inside a level have a StrongPtr (in BaseObject) that references the Level object. This means that the Level
+        //       object is only destroyed, when all StrongPtrs that pointed to it were destroyed. But at the time when the last StrongPtr
+        //       is destroyed, the other object is not yet fully destroyed because the StrongPtr is destroyed in ~BaseObject (and this
+        //       means that e.g. ~Identifiable was not yet called for this object). This means that technically there are still other
+        //       objects alive when ~Level is called. This is the reason why we cannot directly destroy() the Plugins - instead we need
+        //       to call destroyLater() to ensure that no instances from this plugin exist anymore.
+        for (std::list<PluginReference*>::iterator it = this->plugins_.begin(); it != this->plugins_.end(); ++it)
+            (*it)->destroyLater();
+        this->plugins_.clear();
     }
 
@@ -121,8 +153,9 @@
 
         Gametype* rootgametype = orxonox_cast<Gametype*>(identifier->fabricate(this));
-        this->setGametype(rootgametype);
-
-        for (std::list<BaseObject*>::iterator it = this->objects_.begin(); it != this->objects_.end(); ++it)
-            (*it)->setGametype(rootgametype);
+
+        // store a weak-pointer to the gametype to avoid a circular dependency between this level and the gametype (which has a strong-reference on this level)
+        this->setGametype(WeakPtr<Gametype>(rootgametype));
+
+        rootgametype->init(); // call init() AFTER the gametype was set
 
         if (LevelManager::exists())
@@ -134,6 +167,4 @@
     {
         this->objects_.push_back(object);
-        object->setGametype(this->getGametype());
-        object->setLevel(this);
     }
 
@@ -170,5 +201,5 @@
     {
         orxout(internal_info) << "player entered level (id: " << player->getClientID() << ", name: " << player->getName() << ')' << endl;
-        player->setGametype(this->getGametype());
+        player->switchGametype(this->getGametype());
     }
 
@@ -176,5 +207,5 @@
     {
         orxout(internal_info) << "player left level (id: " << player->getClientID() << ", name: " << player->getName() << ')' << endl;
-        player->setGametype(0);
+        player->switchGametype(0);
     }
 }
