Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members

spadesserver.cpp

Go to the documentation of this file.
00001 /* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*-
00002 
00003    this file is part of rcssserver3D
00004    Fri May 9 2003
00005    Copyright (C) 2002,2003 Koblenz University
00006    Copyright (C) 2003 RoboCup Soccer Server 3D Maintenance Group
00007    $Id: spadesserver.cpp,v 1.16 2004/06/19 13:30:38 fruit Exp $
00008 
00009    This program is free software; you can redistribute it and/or modify
00010    it under the terms of the GNU General Public License as published by
00011    the Free Software Foundation; version 2 of the License.
00012 
00013    This program is distributed in the hope that it will be useful,
00014    but WITHOUT ANY WARRANTY; without even the implied warranty of
00015    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016    GNU General Public License for more details.
00017 
00018    You should have received a copy of the GNU General Public License
00019    along with this program; if not, write to the Free Software
00020    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00021 */
00022 #include "spadesserver.h"
00023 
00024 using namespace boost;
00025 using namespace zeitgeist;
00026 using namespace oxygen;
00027 using namespace spades;
00028 using namespace std;
00029 
00030 #include <zeitgeist/corecontext.h>
00031 #include <zeitgeist/logserver/logserver.h>
00032 #include <zeitgeist/scriptserver/scriptserver.h>
00033 #include <oxygen/sceneserver/sceneserver.h>
00034 #include <oxygen/gamecontrolserver/gamecontrolserver.h>
00035 #include <oxygen/monitorserver/monitorserver.h>
00036 #include <oxygen/gamecontrolserver/actionobject.h>
00037 #include <spades/SimEngine.hpp>
00038 #include <spades/EndSimulationEvent.hpp>
00039 #include "spadescreatesenseevent.h"
00040 #include "spadesactevent.h"
00041 
00042 SpadesServer::SpadesServer() :
00043     zeitgeist::Node(), spades::WorldModel(),
00044     mSimEngine(0), mSimulationModeChanged(false),
00045     mOffsetCreateSense(0),mNextInitialCreateSense(0)
00046 {
00047 }
00048 
00049 SpadesServer::~SpadesServer()
00050 {
00051 }
00052 
00053 bool
00054 SpadesServer::ConstructInternal()
00055 {
00056     // setup script variables used to customize the SpadesServer
00057     GetScript()->CreateVariable("Spades.TimePerStep", 0.01f);
00058     GetScript()->CreateVariable("Spades.MonitorInterval", 4);
00059     GetScript()->CreateVariable("Spades.RunIntegratedCommserver", false);
00060     GetScript()->CreateVariable("Spades.CommServersWanted", 1);
00061     GetScript()->CreateVariable("Spades.SendAgentThinkTimes", false);
00062 
00063     return true;
00064 }
00065 
00066 void
00067 SpadesServer::OnLink()
00068 {
00069     mMonitorServer = shared_dynamic_cast<MonitorServer>
00070         (GetCore()->Get("/sys/server/monitor"));
00071 
00072     if (mMonitorServer.get() == 0)
00073     {
00074         GetLog()->Error() << "ERROR: (SpadesServer) MonitorServer not found.\n";
00075     }
00076 
00077     mGameControlServer = shared_dynamic_cast<GameControlServer>
00078         (GetCore()->Get("/sys/server/gamecontrol"));
00079 
00080     if (mGameControlServer.get() == 0)
00081     {
00082         GetLog()->Error() << "ERROR: (SpadesServer) GameControlServer not found.\n";
00083     }
00084 
00085     mSceneServer = shared_dynamic_cast<SceneServer>
00086         (GetCore()->Get("/sys/server/scene"));
00087 
00088     if (mSceneServer.get() == 0)
00089     {
00090         GetLog()->Error() << "ERROR: (SpadesServer) SceneServer not found.\n";
00091     }
00092 
00093     // cache frequently queried ruby values here
00094     mTimePerStep = 0.01f;
00095 }
00096 
00097 void
00098 SpadesServer::OnUnlink()
00099 {
00100     mMonitorServer.reset();
00101     mGameControlServer.reset();
00102     mSceneServer.reset();
00103 }
00104 
00105 spades::SimEngine*
00106 SpadesServer::GetSimEngine()
00107 {
00108     return mSimEngine;
00109 }
00110 
00111 float
00112 SpadesServer::GetTimePerStep() const
00113 {
00114     return mTimePerStep;
00115 }
00116 
00117 int
00118 SpadesServer::GetCommServersWanted() const
00119 {
00120     int commServersWanted = 1;
00121     GetScript()->GetVariable("Spades.CommServersWanted",commServersWanted);
00122 
00123     return std::max<int>(1,commServersWanted);
00124 }
00125 
00126 bool
00127 SpadesServer::GetRunIntegratedCommserver() const
00128 {
00129     bool run_integrated_commserver = false;
00130     GetScript()->GetVariable("Spades.RunIntegratedCommserver",
00131                              run_integrated_commserver);
00132 
00133     return run_integrated_commserver;
00134 }
00135 
00136 int
00137 SpadesServer::GetMonitorInterval() const
00138 {
00139     int monitor_interval = 10;
00140     GetScript()->GetVariable("Spades.MonitorInterval", monitor_interval);
00141 
00142     return monitor_interval;
00143 }
00144 
00145 bool
00146 SpadesServer::GetSendAgentThinkTimes() const
00147 {
00148     bool send_agent_think_times = false;
00149     GetScript()->GetVariable("Spades.SendAgentThinkTimes",
00150                              send_agent_think_times);
00151 
00152     return send_agent_think_times;
00153 }
00154 
00155 boost::shared_ptr<GameControlServer>
00156 SpadesServer::GetGameControlServer() const
00157 {
00158     return mGameControlServer;
00159 }
00160 
00161 void
00162 SpadesServer::StartAgents(const AgentItem& ai)
00163 {
00164     GetLog()->Debug() << "SpadesServer::StartAgents("
00165                       << ai.mAgentType << ", " << ai.mNumber << ")\n";
00166 
00167     if (!mSimEngine || mSimEngine->getNumCommServers () < 1)
00168     {
00169         GetLog()->Error() << "(SpadesServer) No simulation engine or comm server, "
00170                           << "cannot start agents\n" << endl;
00171         return;
00172     }
00173 
00174     AgentTypeDB::AgentTypeConstIterator
00175         at = mSimEngine->getAgentTypeDB()->getAgentType(ai.mAgentType);
00176 
00177     if (at == mSimEngine->getAgentTypeDB()->nullIterator())
00178     {
00179         GetLog()->Error()
00180             << "ERROR: (SpadesServer) could not find agent type "
00181             << ai.mAgentType << endl;
00182         return;
00183     }
00184 
00185     int num = std::max(ai.mNumber, 0);
00186 
00187     while (num > 0)
00188     {
00189         if (mSimEngine->startNewAgent(at) == AGENTID_INVALID)
00190         {
00191             num = 0;
00192             GetLog()->Error()
00193                 << "ERROR: (SpadesServer) starting agent of type " << ai.mAgentType
00194                 << " failed" << endl;
00195         }
00196         --num;
00197     }
00198 }
00199 
00200 void
00201 SpadesServer::Unpause()
00202 {
00203     mNewSimulationMode = SM_RunNormal;
00204     mSimulationModeChanged = true;
00205 }
00206 
00207 void
00208 SpadesServer::QueueAgents(const std::string& agentType, int num)
00209 {
00210     mAgentQueue.push_back(AgentItem(agentType, num));
00211 }
00212 
00213 // ----------------------------------------------------------------------
00214 // SPADES interface methods
00215 EngineParam*
00216 SpadesServer::parseParameters(int argc, const char *const *argv)
00217 {
00218     mParamReader =
00219         shared_static_cast<ParamReader>(GetCore()->New("oxygen/ParamReader"));
00220 
00221     // SimulationEngineMain uses the ParamReader we have to get the
00222     // command line options. It doesn't delete the ParamReader, so we
00223     // can return a simple pointer
00224     mParamReader->getOptions(argc, argv);
00225 
00226     // start an inprocess commserver
00227     mParamReader->setParam("run_integrated_commserver",
00228                            GetRunIntegratedCommserver());
00229 
00230     // send updates to the monitor every nth cycle
00231     mParamReader->setParam("monitor_interval", GetMonitorInterval());
00232 
00233     // don't send think time messages to connected agents
00234     mParamReader->setParam("send_agent_think_times", GetSendAgentThinkTimes());
00235 
00236     return mParamReader.get();
00237 }
00238 
00239 bool
00240 SpadesServer::initialize(SimEngine* pSE)
00241 {
00242     mSimEngine = pSE;
00243     return true;
00244 }
00245 
00246 bool
00247 SpadesServer::finalize()
00248 {
00249     return true;
00250 }
00251 
00252 SimTime
00253 SpadesServer::simToTime(SimTime time_curr, SimTime time_desired)
00254 {
00255     int steps = time_desired - time_curr;
00256     if (steps <= 0)
00257     {
00258         GetLog()->Warning()
00259             << "WARNING: (SpadesServer) will not simulate <= 0 steps\n";
00260         return time_curr;
00261     }
00262 
00263     if (
00264         (mSceneServer.get() == 0) ||
00265         (mGameControlServer.get() == 0)
00266         )
00267     {
00268         GetLog()->Warning()
00269             << "WARNING: (SpadesServer) SceneServer "
00270             << "and/or GameControlServer missing.\n";
00271         return time_curr;
00272     }
00273 
00274     int i = steps;
00275 
00276     while (i > 0)
00277     {
00278         mSceneServer->Update(mTimePerStep);
00279         mGameControlServer->Update(mTimePerStep);
00280         --i;
00281     }
00282 
00283     static bool once = true;
00284     if (mGameControlServer->IsFinished() && once)
00285     {
00286         once = false;
00287         // initiate shutdown here (what time should we use?)
00288         mSimEngine->enqueueEvent(new EndSimulationEvent(time_desired+1));
00289     }
00290 
00291     //    GetLog()->Debug() << "(SpadesServer) time_curr=" << time_curr
00292     //                  << " time_desired=" << time_desired << endl;
00293     //    GetLog()->Debug() << "updated the scene by " << steps - i << " * "
00294     //                << timePerStep << " seconds.\n";
00295 
00296     // return the simulation time when the loop stopped
00297     // (the '- i' makes sense if we exit the while loop earlier)
00298     return time_desired - i;
00299 }
00300 
00301 DataArray
00302 SpadesServer::getMonitorHeaderInfo()
00303 {
00304     if (mMonitorServer.get() == 0)
00305     {
00306         return DataArray();
00307     }
00308 
00309     return DataArray(mMonitorServer->GetMonitorHeaderInfo());
00310 }
00311 
00312 DataArray
00313 SpadesServer::getMonitorInfo(SimTime /*time*/)
00314 {
00315     if (mMonitorServer.get() == 0)
00316     {
00317         return DataArray();
00318     }
00319 
00320     return DataArray(mMonitorServer->GetMonitorInfo());
00321 }
00322 
00323 void
00324 SpadesServer::parseMonitorMessage(const char* data, unsigned datalen)
00325 {
00326     if (mMonitorServer.get() == 0)
00327     {
00328         return;
00329     }
00330 
00331     return mMonitorServer->ParseMonitorMessage(string(data,datalen));
00332 }
00333 
00334 SimTime
00335 SpadesServer::getMinActionLatency() const
00336 {
00337     return 1;
00338 }
00339 
00340 SimTime
00341 SpadesServer::getMinSenseLatency() const
00342 {
00343     return 1;
00344 }
00345 
00346 ActEvent*
00347 SpadesServer::parseAct(SimTime act_received_time, AgentID a, const char* data, unsigned datalen) const
00348 {
00349     if (mGameControlServer.get() == 0)
00350     {
00351         return 0;
00352     }
00353 
00354     shared_ptr<ActionObject::TList> actionList
00355         = mGameControlServer->Parse(a,std::string(data,datalen));
00356 
00357     if (actionList.get() == 0)
00358     {
00359         return 0;
00360     }
00361 
00362     float latency = mGameControlServer->GetActionLatency(a);
00363     // pfr 5/24/2004
00364     // the time act_received_time is the time that the commserver reports as the actions being
00365     // sent. Notably, this includes the thinking latency.
00366     // This is NOT the same as mSimEngine->getSimulationTime() (which is what was here before)
00367     // since SPADES does out of order event reception and processing reasoning
00368     SimTime arrival = act_received_time + static_cast<int>(latency / GetTimePerStep());
00369 
00370     return new SpadesActEvent(arrival, a, actionList);
00371 }
00372 
00373 void
00374 SpadesServer::pauseModeCallback()
00375 {
00376     // the first time pauseModeCallback will be called is immediatly
00377     // after startup when SPADES is in SM_PausedInitial mode
00378 
00379     if (mSimEngine->getSimulationMode() == SM_PausedInitial)
00380     {
00381         int numConnected = mSimEngine->getNumCommServers();
00382         GetLog()->Normal() << "(SpadesServer) waiting for a total of "
00383                            << GetCommServersWanted()
00384                            << " CommServers, " << numConnected
00385                            << " already connected\n";
00386 
00387         if (numConnected >= GetCommServersWanted())
00388         {
00389             Unpause();
00390         } else
00391         {
00392             return;
00393         }
00394     }
00395 
00396     if (
00397         (mGameControlServer.get() != 0) &&
00398         (! mAgentQueue.empty())
00399         )
00400     {
00401         int agentCount = 0;
00402         for (
00403             TAgentQueue::iterator iter = mAgentQueue.begin();
00404             iter != mAgentQueue.end();
00405             ++iter
00406             )
00407         {
00408             agentCount += (*iter).mNumber;
00409         }
00410 
00411         // todo: query the gcs, prob: currently deltaSense returned
00412         // for an agentId which is unknown at this point
00413         float deltaSense = 0.20;
00414         float offsetSec = deltaSense / agentCount;
00415 
00416         mOffsetCreateSense = (offsetSec / GetTimePerStep());
00417         mNextInitialCreateSense = mSimEngine->getSimulationTime() + 1;
00418 
00419         GetLog()->Debug() << "(SpadesServer) Starting "
00420                            << agentCount << " agents (delta sense: " << deltaSense<< ")\n"
00421                            << "with an CreateSenseEvent offset of "
00422                            << mOffsetCreateSense << " (" << offsetSec << " seconds)\n"
00423                            << "starting at simTime " << mNextInitialCreateSense << "\n";
00424 
00425         while (! mAgentQueue.empty())
00426         {
00427             StartAgents(mAgentQueue.front());
00428             mAgentQueue.pop_front();
00429         }
00430     }
00431 
00432     if (mSimulationModeChanged)
00433     {
00434         mSimEngine->changeSimulationMode(mNewSimulationMode);
00435         mSimulationModeChanged = false;
00436     }
00437 }
00438 
00439 bool
00440 SpadesServer::agentConnect(AgentID agent, AgentTypeDB::AgentTypeConstIterator /*at*/)
00441 {
00442     // try to register the agent to the game control server
00443     shared_ptr<GameControlServer> gcs = GetGameControlServer();
00444 
00445     if (
00446         (mGameControlServer.get() == 0) ||
00447         (! mGameControlServer->AgentConnect(static_cast<int>(agent)))
00448         )
00449     {
00450         GetLog()->Normal()
00451             << "(SpadesServer) ERROR: cannot register agent "
00452             << "to the GameControlServer\n";
00453         return false;
00454     }
00455 
00456     // schedule the first SpadesCreateSenseEvent
00457     SimTime time = static_cast<SimTime>(mNextInitialCreateSense);
00458     SpadesCreateSenseEvent* event = new SpadesCreateSenseEvent
00459         (time,agent);
00460 
00461     SimTime now = mSimEngine->getSimulationTime();
00462     GetLog()->Normal()
00463         << "(SpadesServer) agentConnect (id " << agent
00464         << ") at simlation time " << now << ".\n"
00465         << "Initial CreateSenseEvent scheduled at "
00466         << time << "\n";
00467 
00468     mNextInitialCreateSense += mOffsetCreateSense;
00469     mSimEngine->enqueueEvent(event);
00470 
00471     return true;
00472 }
00473 
00474 bool
00475 SpadesServer::agentDisappear(AgentID agent, AgentLostReason /*reason*/)
00476 {
00477     if (mGameControlServer.get() == 0)
00478     {
00479         return false;
00480     }
00481 
00482     return mGameControlServer->AgentDisappear(static_cast<int>(agent));
00483 }
00484 
00485 void
00486 SpadesServer::notifyCommserverConnect(ServerID /*s*/)
00487 {
00488 }
00489 
00490 void
00491 SpadesServer::notifyCommserverDisconnect(ServerID /*s*/)
00492 {
00493 }
00494 
00495 void
00496 SpadesServer::UpdateCached()
00497 {
00498     GetScript()->GetVariable("Spades.TimePerStep", mTimePerStep);
00499 }

Generated on Thu Apr 6 15:25:40 2006 for rcssserver3d by  doxygen 1.4.4