From: Markus R. <rol...@us...> - 2005-12-05 21:21:30
|
Update of /cvsroot/simspark/simspark/spark/oxygen/spadesserver In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv15620/spadesserver Added Files: paramreader.cpp paramreader.h paramreader_c.cpp paramstorer.cpp paramstorer.h spadesactevent.cpp spadesactevent.h spadescreatesenseevent.cpp spadescreatesenseevent.h spadesserver.cpp spadesserver.h spadesserver_c.cpp Log Message: --- NEW FILE: spadescreatesenseevent.h --- /* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- this file is part of rcssserver3D Fri May 9 2003 Copyright (C) 2002,2003 Koblenz University Copyright (C) 2003 RoboCup Soccer Server 3D Maintenance Group $Id: spadescreatesenseevent.h,v 1.1 2005/12/05 21:21:18 rollmark Exp $ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef OXYGEN_SPADESCREATESENSEEVENT_H #define OXYGEN_SPADESCREATESENSEEVENT_H #include <spades/CreateSenseEvent.hpp> namespace oxygen { #if 0 } #endif /** SpadesCreateSenseEvent implements the spades::CreateSenseEvent interface. It's purpose is to create a SenseEvent and to schedule it's successor SpadesCreateEvent. A note about the implementation: SpadesCreateSenseEvent uses the SpadesServer and the GameControlServer to do it's job. However it cannot be zeitgeist class, as this involves that the corresponding class object holds a shared pointer to every instance of this class. However spades is not aware of these shared pointers and destructs a registered ParamStorer instance using delete without notifying the shared pointers. This would result in dangling references. */ class SpadesCreateSenseEvent : public spades::CreateSenseEvent { public: SpadesCreateSenseEvent (spades::SimTime t, spades::AgentID a) : CreateSenseEvent (t, a) {} virtual ~SpadesCreateSenseEvent () {} virtual void Print (std::ostream & o) const; virtual bool realizeEventWorldModel(spades::WorldModel* pWM); virtual spades::SenseEvent* createSense(spades::WorldModel* p); }; } // namespace oxygen #endif // OXYGEN_SPADESCREATESENSEEVENT_H --- NEW FILE: spadescreatesenseevent.cpp --- /* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- this file is part of rcssserver3D Fri May 9 2003 Copyright (C) 2002,2003 Koblenz University Copyright (C) 2003 RoboCup Soccer Server 3D Maintenance Group $Id: spadescreatesenseevent.cpp,v 1.1 2005/12/05 21:21:18 rollmark Exp $ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "spadescreatesenseevent.h" #include "spadesserver.h" #include <spades/SenseEvent.hpp> #include <zeitgeist/logserver/logserver.h> #include <oxygen/agentaspect/agentaspect.h> #include <oxygen/gamecontrolserver/gamecontrolserver.h> #include <oxygen/gamecontrolserver/baseparser.h> using namespace oxygen; using namespace spades; using namespace std; using namespace boost; void SpadesCreateSenseEvent::Print (std::ostream & o) const { o << "SpadesCreateSenseEvent(" << getTime () << ") for " << getAgent(); } bool SpadesCreateSenseEvent::realizeEventWorldModel(spades::WorldModel* pWM) { // we can't create a shared_ptr to the SpadesServer here, as this // shared_ptr wouldn't know of other shared_ptrs to the // SpadesServer SpadesServer* spadesServer = dynamic_cast<SpadesServer*>(pWM); if (spadesServer == 0) { // we can't use the LogServer here :( return false; } shared_ptr<GameControlServer> gcs(spadesServer->GetGameControlServer()); if (gcs.get() == 0) { spadesServer->GetLog()->Error() << "(SpadesCreateSenseEvent) GameControlServer not found.\n"; return false; } // query the game control server for the time until the next // SpadesCreateSenseInterval should be realized. The gameControlServer // returns this time in seconds float deltaSense = gcs->GetSenseInterval(static_cast<int>(getAgent())); // calculate the corresponding amount of time steps int senseInterval = static_cast<int>(deltaSense / spadesServer->GetTimePerStep()); // schedule the next CreateSenseEvent SimEngine* simEngine = spadesServer->GetSimEngine(); if (simEngine == 0) { spadesServer->GetLog()->Error() << "(SpadesCreateSenseEvent) spades SimEngine not found.\n"; return false; } SpadesCreateSenseEvent* event = new SpadesCreateSenseEvent (getTime() + senseInterval, getAgent()); simEngine->enqueueEvent(event); return true; } spades::SenseEvent* SpadesCreateSenseEvent::createSense(spades::WorldModel* p) { SpadesServer* spadesServer = dynamic_cast<SpadesServer*>(p); if (spadesServer == 0) { return 0; } shared_ptr<GameControlServer> gcs(spadesServer->GetGameControlServer()); if (gcs.get() == 0) { spadesServer->GetLog()->Error() << "(SpadesCreateSenseEvent) GameControlServer not found.\n"; return 0; } shared_ptr<BaseParser> parser = gcs->GetParser(); if (parser.get() == 0) { spadesServer->GetLog()->Error() << "ERROR: (SpadesCreateSenseEvent) got no parser from " << " the GameControlServer" << endl; return 0; } // lookup the AgentAspect int id = getAgent(); shared_ptr<AgentAspect> agent = gcs->GetAgentAspect(id); if (agent.get() == 0) { spadesServer->GetLog()->Error() << "ERROR: (SpadesCreateSenseEvent) got no AgentAspect for id " << id << " from the GameControlServer" << endl; return 0; } // get a list of senses from the agent and generate a string // describing them shared_ptr<PredicateList> senseList = agent->QueryPerceptors(); std::string senses = parser->Generate(senseList); // create the sense event float senseDelay = gcs->GetSenseLatency(getAgent()); SimTime senseArriveTime = getTime() + static_cast<int>(senseDelay / spadesServer->GetTimePerStep()); // // what's the correct value for ttype here ? // (see spades/shared/sharedtypes.hpp) // ThinkingType ttype = TT_Regular; SenseEvent* event = new SenseEvent (ttype, getTime(), senseArriveTime, getAgent()); event->setData(senses); return event; } --- NEW FILE: paramreader_c.cpp --- /* -*- mode: c++ -*- this file is part of rcssserver3D Fri May 9 2003 Copyright (C) 2003 Koblenz University $Id: paramreader_c.cpp,v 1.1 2005/12/05 21:21:18 rollmark Exp $ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "paramreader.h" using namespace oxygen; void CLASS(ParamReader)::DefineClass() { DEFINE_BASECLASS(zeitgeist/Node); } --- NEW FILE: paramstorer.cpp --- /* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- this file is part of rcssserver3D Fri May 9 2003 Copyright (C) 2002,2003 Koblenz University Copyright (C) 2003 RoboCup Soccer Server 3D Maintenance Group $Id: paramstorer.cpp,v 1.1 2005/12/05 21:21:18 rollmark Exp $ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "paramstorer.h" using namespace oxygen; int ParamStorer::readCmdLineArgs(const std::string& key, int argc, const char* const* argv) { if (mParamReader != NULL) { return mParamReader->readCmdLineArgs(key,argc,argv); } return 0; } --- NEW FILE: paramstorer.h --- /* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- this file is part of rcssserver3D Fri May 9 2003 Copyright (C) 2002,2003 Koblenz University Copyright (C) 2003 RoboCup Soccer Server 3D Maintenance Group $Id: paramstorer.h,v 1.1 2005/12/05 21:21:18 rollmark Exp $ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef OXYGEN_PARAMSTORER_H__ #define OXYGEN_PARAMSTORER_H__ #include "paramreader.h" #include <spades/ParamReader.hpp> namespace oxygen { /** This class implements the spades::ParamReader::ParamStorer interface. It's purpose is to enable the user to set ruby variables using the command line. A note about the implementation: ParamStorer uses the ParamReader class to do the real parsing. This has the following reason. In order to access the ScriptServer to modify ruby variables the ParamStorer must be a ZeitGeist class. This involves that the corresponding class object holds a shared pointer to every instance of this class. However spades is not aware of these shared pointers and destructs a registered ParamStorer instance using delete without notifying the shared pointers. This would result in dangling references. In order to play well with spades this class is not derived from Zeitgeist::object. In order to access the ScriptServer this class uses the ParamReader instance. */ class ParamStorer : public spades::ParamReader::ParamStorer { public: ParamStorer(oxygen::ParamReader* paramReader) : spades::ParamReader::ParamStorer(), mParamReader(paramReader) {} virtual int readArgsFrom(const std::string& /*key*/, const char* /*fileid*/, const char* /*path*/, std::istream& /*is*/, bool /*have_argument*/) { // we read nothing from any files return RR_None; } virtual void print(std::ostream& /*o*/) const { // no output } // returns the number of args processed // otherwise see the RR_ values above virtual int readCmdLineArgs(const std::string& key, int argc, const char* const* argv); protected: /** The ParamReader we use to do the parsing */ oxygen::ParamReader* mParamReader; }; } // namespace oxygen #endif // OXYGEN_PARAMSTORER_H__ --- NEW FILE: spadesactevent.h --- /* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- this file is part of rcssserver3D Fri May 9 2003 Copyright (C) 2002,2003 Koblenz University Copyright (C) 2003 RoboCup Soccer Server 3D Maintenance Group $Id: spadesactevent.h,v 1.1 2005/12/05 21:21:18 rollmark Exp $ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef OXYGEN_SPADESACTEVENT_H #define OXYGEN_SPADESACTEVENT_H #include <spades/ActEvent.hpp> #include <oxygen/gamecontrolserver/actionobject.h> namespace oxygen { #if 0 } #endif class SpadesActEvent : public spades::ActEvent { public: SpadesActEvent ( spades::SimTime t, spades::AgentID a, boost::shared_ptr<ActionObject::TList> actionList ) : spades::ActEvent(t, a), mActionList(actionList) {}; virtual ~SpadesActEvent (){} virtual void Print (std::ostream & o) const; /** realizes the stored list of ActionObjects. As a sanity check it returns whether the world model did anything with this event. In our case always true. */ virtual bool realizeEventWorldModel(spades::WorldModel* pWM); protected: boost::shared_ptr<ActionObject::TList> mActionList; }; } // namespace oxygen #endif // OXYGEN_SPADESACTEVENT_H --- NEW FILE: paramreader.h --- /* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- this file is part of rcssserver3D Fri May 9 2003 Copyright (C) 2002,2003 Koblenz University Copyright (C) 2003 RoboCup Soccer Server 3D Maintenance Group $Id: paramreader.h,v 1.1 2005/12/05 21:21:18 rollmark Exp $ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef OXYGEN_PARAMETERREADER_H #define OXYGEN_PARAMETERREADER_H #include <zeitgeist/class.h> #include <zeitgeist/leaf.h> #include <spades/EngineParam.hpp> namespace oxygen { /*! */ class ParamReader : public zeitgeist::Leaf, public spades::EngineParam { public: ParamReader(); /** returns the number of args processed otherwise see the spades RR_values. This method is called from within the ParamStorer. */ int readCmdLineArgs(const std::string& key, int argc, const char* const* argv); }; DECLARE_CLASS(ParamReader); } // namespace oxygen #endif // OXYGEN_PARAMETERREADER_H --- NEW FILE: spadesserver_c.cpp --- /* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- this file is part of rcssserver3D Fri May 9 2003 Copyright (C) 2002,2003 Koblenz University Copyright (C) 2003 RoboCup Soccer Server 3D Maintenance Group $Id: spadesserver_c.cpp,v 1.1 2005/12/05 21:21:18 rollmark Exp $ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "spadesserver.h" using namespace oxygen; using namespace std; FUNCTION(SpadesServer,queueAgents) { string inAgentType; int inNum; if ( (in.GetSize() != 2) || (! in.GetValue(in[0],inAgentType)) || (! in.GetValue(in[1],inNum)) ) { return false; } obj->QueueAgents(inAgentType,inNum); return true; } void CLASS(SpadesServer)::DefineClass() { DEFINE_BASECLASS(zeitgeist/Node); DEFINE_FUNCTION(queueAgents); } --- NEW FILE: paramreader.cpp --- /* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- this file is part of rcssserver3D Fri May 9 2003 Copyright (C) 2002,2003 Koblenz University Copyright (C) 2003 RoboCup Soccer Server 3D Maintenance Group $Id: paramreader.cpp,v 1.1 2005/12/05 21:21:18 rollmark Exp $ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "paramreader.h" #include "paramstorer.h" #include <zeitgeist/logserver/logserver.h> #include <zeitgeist/scriptserver/scriptserver.h> #include <sstream> using namespace zeitgeist; using namespace oxygen; using namespace boost; using namespace std; ParamReader::ParamReader() : zeitgeist::Leaf(), spades::EngineParam() { addParamStorer(new oxygen::ParamStorer(this)); } int ParamReader::readCmdLineArgs(const std::string& key, int argc, const char* const* argv) { // lookup the ScriptServer if (argc < 2) { return spades::ParamReader::ParamStorer::RR_None; } // check if varName is valid if (! GetScript()->ExistsVariable(key)) { GetLog()->Warning() << "WARNING: (ParamReader) Unknown variable '" << key << "'\n"; return spades::ParamReader::ParamStorer::RR_FormatErr; } // take next as the value std::string value = * (argv + 1); // eval "<key> = <value>" using ruby stringstream ss; ss << key << "=" << value; if (GetScript()->Eval(ss.str())) { GetLog()->Normal() << "(ParamReader) set '" << key << "' to " << value << "\n"; } return 1; } --- NEW FILE: spadesactevent.cpp --- /* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- this file is part of rcssserver3D Fri May 9 2003 Copyright (C) 2002,2003 Koblenz University Copyright (C) 2003 RoboCup Soccer Server 3D Maintenance Group $Id: spadesactevent.cpp,v 1.1 2005/12/05 21:21:18 rollmark Exp $ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "spadesactevent.h" #include "spadesserver.h" #include <zeitgeist/logserver/logserver.h> #include <oxygen/gamecontrolserver/gamecontrolserver.h> #include <oxygen/agentaspect/agentaspect.h> using namespace oxygen; using namespace zeitgeist; using namespace boost; using namespace std; void SpadesActEvent::Print (std::ostream & /*o*/) const { } bool SpadesActEvent::realizeEventWorldModel(spades::WorldModel* pWM) { // we can't create a shared_ptr to the SpadesServer here, as this // shared_ptr wouldn't know of other shared_ptrs to the // SpadesServer SpadesServer* spadesServer = dynamic_cast<SpadesServer*>(pWM); if (spadesServer == NULL) { // we can't use the LogServer here :( return false; } shared_ptr<GameControlServer> gcs = spadesServer->GetGameControlServer(); if (gcs.get() == 0) { spadesServer->GetLog()->Error() << "(SpadesActEvent) GameControlServer not found." << endl; return false; } // lookup the AgentAspect int id = getAgent(); shared_ptr<AgentAspect> agent = gcs->GetAgentAspect(id); if (agent.get() == 0) { spadesServer->GetLog()->Warning() << "ERROR: (SpadesActEvent) no AgentAspect for id " << id << "found." << endl; return false; } // realize the stored actions agent->RealizeActions(mActionList); // indicate that we 'did something' with the event return true; } --- NEW FILE: spadesserver.h --- /* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- this file is part of rcssserver3D Fri May 9 2003 Copyright (C) 2002,2003 Koblenz University Copyright (C) 2003 RoboCup Soccer Server 3D Maintenance Group $Id: spadesserver.h,v 1.1 2005/12/05 21:21:18 rollmark Exp $ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef OXYGEN_SPADESSERVER_H #define OXYGEN_SPADESSERVER_H #include <spades/enginemain.hpp> #include <spades/SimEngine.hpp> #include <zeitgeist/class.h> #include <zeitgeist/node.h> #include "paramreader.h" #include <queue> namespace oxygen { class GameControlServer; class MonitorServer; class SceneServer; /*! The SpadesServer serves as an interface between the SceneServer and the agents */ class SpadesServer : public zeitgeist::Node, public spades::WorldModel { public: SpadesServer(); ~SpadesServer(); // Methods starting with small letters are SPADES interface methods. // Methods with a initial capital letter are additional methods needed // for the zeitgeist framework. /** setup script variables used to customize the SpadesServer */ virtual bool ConstructInternal(); /** set up GameControlServer and MonitorServer reference */ virtual void OnLink(); /** reset GameControlServer and MonitorServer reference */ virtual void OnUnlink(); /** helper function to locate the game control server */ boost::shared_ptr<GameControlServer> GetGameControlServer() const; /** returns the amount of time in seconds a single simulation step corresponds to. */ float GetTimePerStep() const; /** Get the value of the Spades.RunIntegratedCommserver variable. * \return true if the variable is set to true, false otherwise. */ bool GetRunIntegratedCommserver() const; /** Get the value of the Spades.CommServersWanted variable. On startup SpadesServer will wait until at least 'CommServersWanted' CommServers have connected before it initially unpauses the simulation. */ int GetCommServersWanted() const; /** Get the value of the Spades.MonitorInterval variable. * \return the number of simulation steps per monitor message. */ int GetMonitorInterval() const; /** Get the value of the Spades.SendAgentThinkTimes variable. */ bool GetSendAgentThinkTimes() const; /** queue up agents to be started. \param agentType agent type to be found in the SPADES agent database. \param num number of agents to be started of the given type. */ void QueueAgents(const std::string& agentType="default", int num=1); /** set simulation mode to normal */ void Unpause(); /** update cached variables */ virtual void UpdateCached(); // ---------------------------------------------------------------------- // SPADES interface methods start here /** You probably want to inherit some parameters from EngineParam and use that to parse the commandline. See the ParamReader class. */ spades::EngineParam* parseParameters(int argc, const char* const *argv); /** Most of the real initialization/finalization work should be * done here. We do this so that the SimEngine can initialize * after this class is created. * * @param pSE a pointer to the spades simulation engine * @return true */ bool initialize(spades::SimEngine* pSE); /** returns a pointer to the spades simulation engine */ spades::SimEngine* GetSimEngine(); /** @return true */ bool finalize(); /** This function should advance the world forward. Events can be * enqueed from this function. The time does *not* have to * advance all the way to the time_desired, and if you put events * in the queue, you should not advance past the time of those * events. The simulation time here is an integer type, so the * SpadesServer has to know how big a simulation step is. * * @param time_curr the current simulation step * @param time_desired the desired simulation step * @return a new simulation time t (time_curr <= t <= time_desired) */ spades::SimTime simToTime(spades::SimTime time_curr, spades::SimTime time_desired); /** Monitors are programs that can open up a connection to the * engine and get periodic updates about the state of the * world. These next three functions support this. */ /** This function is called once for every monitor. It should * return any header/setup information that is needed. */ spades::DataArray getMonitorHeaderInfo(); /** This function will be called periodically to get information * about the current state of the world. The format is completely * determined by what the monitors will expect; no processing is * done by the simulation engine */ spades::DataArray getMonitorInfo(spades::SimTime time); /** If a monitor sends information to the world model, this * function is called to process it. Note that only the data * section of the message (not the ID part which indicates that it * is a message for the world model and not the simulation engine) * is included here. If you need to keep the data, you must copy * it */ void parseMonitorMessage(const char* data, unsigned datalen); /** There is a latency (in simulation time) between when an action * is sent by the agent and when it takes effect. This function * needs to return the minimum of all possible values of that * latency. This is used to reason about causality */ spades::SimTime getMinActionLatency() const; /** Similar to getMinActionLatency, but the latency between when * the sensation is generated from the world and when it is * received by the agent */ spades::SimTime getMinSenseLatency() const; /** This function parses the action string received from the * agents Note that this method is const! parsing the act can * *not* affect the world at all, since this could then violate * causality. Also, at some point this functionality may be * moved to the communication server (which manages communication * with the agents) */ spades::ActEvent* parseAct(spades::SimTime t, spades::AgentID a, const char* data, unsigned datalen) const; /** When the simulation is paused, this is called peridically At * some point, this function should unpause the simulation The * simulation starts out in paused mode */ void pauseModeCallback(); /** The world model initiates startup requests for agents. This * function is called once the agent has been started * successfully */ bool agentConnect(spades::AgentID agent, spades::AgentTypeDB::AgentTypeConstIterator at); /** Any time an agent leaves the simulation (whether by crash, * graceful exit request, etc.), this function is called so that * the world model can update it's data structures */ bool agentDisappear(spades::AgentID agent, spades::AgentLostReason reason); /** Called every time a comm server connects. Usually, this can be * ignored as the WorldModel does not need to know when and how * many commservers connect, unless it wants to do it's own load * balancing */ void notifyCommserverConnect(spades::ServerID s); /** Called every time a comm server dsiconnects. Usually, this can * be ignored as the WorldModel does not need to know when and * how many commservers connect, unless it wants to do it's own * load balancing */ void notifyCommserverDisconnect(spades::ServerID s); protected: struct AgentItem { AgentItem(const std::string& agentType = "", int num = 0) : mAgentType(agentType), mNumber(num) {} std::string mAgentType; int mNumber; }; typedef std::list<AgentItem> TAgentQueue; /** Start up a number of agents of a given type. \param ai contains the agent type from the agent database and the number of agents to start. */ void StartAgents(const AgentItem& ai); private: /** the Spades simulation engine */ spades::SimEngine* mSimEngine; /** our commandline parser */ boost::shared_ptr<ParamReader> mParamReader; /** flag if there is a simulation mode change scheduled */ bool mSimulationModeChanged; /** the next simulation mode for a mode change */ spades::SimulationMode mNewSimulationMode; /** a queue of agents to be started up */ TAgentQueue mAgentQueue; /** the simTime offset in the scheduled times for the agents CreateSenseEvent */ float mOffsetCreateSense; /** the initial CreateSenseEvent simTime scheduled for the next connecing agent */ float mNextInitialCreateSense; /** a cached reference to the monitor server */ boost::shared_ptr<MonitorServer> mMonitorServer; /** a cached reference to the GameControlServer */ boost::shared_ptr<GameControlServer> mGameControlServer; /** a cached reference to the SceneServer */ boost::shared_ptr<SceneServer> mSceneServer; /** the cached Spades.TimePerStep value */ float mTimePerStep; }; DECLARE_CLASS(SpadesServer); } // namespace oxygen #endif // OXYGEN_SPADESSERVER_H --- NEW FILE: spadesserver.cpp --- /* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- this file is part of rcssserver3D Fri May 9 2003 Copyright (C) 2002,2003 Koblenz University Copyright (C) 2003 RoboCup Soccer Server 3D Maintenance Group $Id: spadesserver.cpp,v 1.1 2005/12/05 21:21:18 rollmark Exp $ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "spadesserver.h" using namespace boost; using namespace zeitgeist; using namespace oxygen; using namespace spades; using namespace std; #include <zeitgeist/corecontext.h> #include <zeitgeist/logserver/logserver.h> #include <zeitgeist/scriptserver/scriptserver.h> #include <oxygen/sceneserver/sceneserver.h> #include <oxygen/gamecontrolserver/gamecontrolserver.h> #include <oxygen/monitorserver/monitorserver.h> #include <oxygen/gamecontrolserver/actionobject.h> #include <spades/SimEngine.hpp> #include <spades/EndSimulationEvent.hpp> #include "spadescreatesenseevent.h" #include "spadesactevent.h" SpadesServer::SpadesServer() : zeitgeist::Node(), spades::WorldModel(), mSimEngine(0), mSimulationModeChanged(false), mOffsetCreateSense(0),mNextInitialCreateSense(0) { } SpadesServer::~SpadesServer() { } bool SpadesServer::ConstructInternal() { // setup script variables used to customize the SpadesServer GetScript()->CreateVariable("Spades.TimePerStep", 0.01f); GetScript()->CreateVariable("Spades.MonitorInterval", 4); GetScript()->CreateVariable("Spades.RunIntegratedCommserver", false); GetScript()->CreateVariable("Spades.CommServersWanted", 1); GetScript()->CreateVariable("Spades.SendAgentThinkTimes", false); return true; } void SpadesServer::OnLink() { mMonitorServer = shared_dynamic_cast<MonitorServer> (GetCore()->Get("/sys/server/monitor")); if (mMonitorServer.get() == 0) { GetLog()->Error() << "ERROR: (SpadesServer) MonitorServer not found.\n"; } mGameControlServer = shared_dynamic_cast<GameControlServer> (GetCore()->Get("/sys/server/gamecontrol")); if (mGameControlServer.get() == 0) { GetLog()->Error() << "ERROR: (SpadesServer) GameControlServer not found.\n"; } mSceneServer = shared_dynamic_cast<SceneServer> (GetCore()->Get("/sys/server/scene")); if (mSceneServer.get() == 0) { GetLog()->Error() << "ERROR: (SpadesServer) SceneServer not found.\n"; } // cache frequently queried ruby values here mTimePerStep = 0.01f; } void SpadesServer::OnUnlink() { mMonitorServer.reset(); mGameControlServer.reset(); mSceneServer.reset(); } spades::SimEngine* SpadesServer::GetSimEngine() { return mSimEngine; } float SpadesServer::GetTimePerStep() const { return mTimePerStep; } int SpadesServer::GetCommServersWanted() const { int commServersWanted = 1; GetScript()->GetVariable("Spades.CommServersWanted",commServersWanted); return std::max<int>(1,commServersWanted); } bool SpadesServer::GetRunIntegratedCommserver() const { bool run_integrated_commserver = false; GetScript()->GetVariable("Spades.RunIntegratedCommserver", run_integrated_commserver); return run_integrated_commserver; } int SpadesServer::GetMonitorInterval() const { int monitor_interval = 10; GetScript()->GetVariable("Spades.MonitorInterval", monitor_interval); return monitor_interval; } bool SpadesServer::GetSendAgentThinkTimes() const { bool send_agent_think_times = false; GetScript()->GetVariable("Spades.SendAgentThinkTimes", send_agent_think_times); return send_agent_think_times; } boost::shared_ptr<GameControlServer> SpadesServer::GetGameControlServer() const { return mGameControlServer; } void SpadesServer::StartAgents(const AgentItem& ai) { GetLog()->Debug() << "SpadesServer::StartAgents(" << ai.mAgentType << ", " << ai.mNumber << ")\n"; if (!mSimEngine || mSimEngine->getNumCommServers () < 1) { GetLog()->Error() << "(SpadesServer) No simulation engine or comm server, " << "cannot start agents\n" << endl; return; } AgentTypeDB::AgentTypeConstIterator at = mSimEngine->getAgentTypeDB()->getAgentType(ai.mAgentType); if (at == mSimEngine->getAgentTypeDB()->nullIterator()) { GetLog()->Error() << "ERROR: (SpadesServer) could not find agent type " << ai.mAgentType << endl; return; } int num = std::max(ai.mNumber, 0); while (num > 0) { if (mSimEngine->startNewAgent(at) == AGENTID_INVALID) { num = 0; GetLog()->Error() << "ERROR: (SpadesServer) starting agent of type " << ai.mAgentType << " failed" << endl; } --num; } } void SpadesServer::Unpause() { mNewSimulationMode = SM_RunNormal; mSimulationModeChanged = true; } void SpadesServer::QueueAgents(const std::string& agentType, int num) { mAgentQueue.push_back(AgentItem(agentType, num)); } // ---------------------------------------------------------------------- // SPADES interface methods EngineParam* SpadesServer::parseParameters(int argc, const char *const *argv) { mParamReader = shared_static_cast<ParamReader>(GetCore()->New("oxygen/ParamReader")); // SimulationEngineMain uses the ParamReader we have to get the // command line options. It doesn't delete the ParamReader, so we // can return a simple pointer mParamReader->getOptions(argc, argv); // start an inprocess commserver mParamReader->setParam("run_integrated_commserver", GetRunIntegratedCommserver()); // send updates to the monitor every nth cycle mParamReader->setParam("monitor_interval", GetMonitorInterval()); // don't send think time messages to connected agents mParamReader->setParam("send_agent_think_times", GetSendAgentThinkTimes()); return mParamReader.get(); } bool SpadesServer::initialize(SimEngine* pSE) { mSimEngine = pSE; return true; } bool SpadesServer::finalize() { return true; } SimTime SpadesServer::simToTime(SimTime time_curr, SimTime time_desired) { int steps = time_desired - time_curr; if (steps <= 0) { GetLog()->Warning() << "WARNING: (SpadesServer) will not simulate <= 0 steps\n"; return time_curr; } if ( (mSceneServer.get() == 0) || (mGameControlServer.get() == 0) ) { GetLog()->Warning() << "WARNING: (SpadesServer) SceneServer " << "and/or GameControlServer missing.\n"; return time_curr; } int i = steps; while (i > 0) { mSceneServer->Update(mTimePerStep); mGameControlServer->Update(mTimePerStep); --i; } static bool once = true; if (mGameControlServer->IsFinished() && once) { once = false; // initiate shutdown here (what time should we use?) mSimEngine->enqueueEvent(new EndSimulationEvent(time_desired+1)); } // GetLog()->Debug() << "(SpadesServer) time_curr=" << time_curr // << " time_desired=" << time_desired << endl; // GetLog()->Debug() << "updated the scene by " << steps - i << " * " // << timePerStep << " seconds.\n"; // return the simulation time when the loop stopped // (the '- i' makes sense if we exit the while loop earlier) return time_desired - i; } DataArray SpadesServer::getMonitorHeaderInfo() { if (mMonitorServer.get() == 0) { return DataArray(); } return DataArray(mMonitorServer->GetMonitorHeaderInfo()); } DataArray SpadesServer::getMonitorInfo(SimTime /*time*/) { if (mMonitorServer.get() == 0) { return DataArray(); } return DataArray(mMonitorServer->GetMonitorInfo()); } void SpadesServer::parseMonitorMessage(const char* data, unsigned datalen) { if (mMonitorServer.get() == 0) { return; } return mMonitorServer->ParseMonitorMessage(string(data,datalen)); } SimTime SpadesServer::getMinActionLatency() const { return 1; } SimTime SpadesServer::getMinSenseLatency() const { return 1; } ActEvent* SpadesServer::parseAct(SimTime act_received_time, AgentID a, const char* data, unsigned datalen) const { if (mGameControlServer.get() == 0) { return 0; } shared_ptr<ActionObject::TList> actionList = mGameControlServer->Parse(a,std::string(data,datalen)); if (actionList.get() == 0) { return 0; } float latency = mGameControlServer->GetActionLatency(a); // pfr 5/24/2004 // the time act_received_time is the time that the commserver reports as the actions being // sent. Notably, this includes the thinking latency. // This is NOT the same as mSimEngine->getSimulationTime() (which is what was here before) // since SPADES does out of order event reception and processing reasoning SimTime arrival = act_received_time + static_cast<int>(latency / GetTimePerStep()); return new SpadesActEvent(arrival, a, actionList); } void SpadesServer::pauseModeCallback() { // the first time pauseModeCallback will be called is immediatly // after startup when SPADES is in SM_PausedInitial mode if (mSimEngine->getSimulationMode() == SM_PausedInitial) { int numConnected = mSimEngine->getNumCommServers(); GetLog()->Normal() << "(SpadesServer) waiting for a total of " << GetCommServersWanted() << " CommServers, " << numConnected << " already connected\n"; if (numConnected >= GetCommServersWanted()) { Unpause(); } else { return; } } if ( (mGameControlServer.get() != 0) && (! mAgentQueue.empty()) ) { int agentCount = 0; for ( TAgentQueue::iterator iter = mAgentQueue.begin(); iter != mAgentQueue.end(); ++iter ) { agentCount += (*iter).mNumber; } // todo: query the gcs, prob: currently deltaSense returned // for an agentId which is unknown at this point float deltaSense = 0.20; float offsetSec = deltaSense / agentCount; mOffsetCreateSense = (offsetSec / GetTimePerStep()); mNextInitialCreateSense = mSimEngine->getSimulationTime() + 1; GetLog()->Debug() << "(SpadesServer) Starting " << agentCount << " agents (delta sense: " << deltaSense<< ")\n" << "with an CreateSenseEvent offset of " << mOffsetCreateSense << " (" << offsetSec << " seconds)\n" << "starting at simTime " << mNextInitialCreateSense << "\n"; while (! mAgentQueue.empty()) { StartAgents(mAgentQueue.front()); mAgentQueue.pop_front(); } } if (mSimulationModeChanged) { mSimEngine->changeSimulationMode(mNewSimulationMode); mSimulationModeChanged = false; } } bool SpadesServer::agentConnect(AgentID agent, AgentTypeDB::AgentTypeConstIterator /*at*/) { // try to register the agent to the game control server shared_ptr<GameControlServer> gcs = GetGameControlServer(); if ( (mGameControlServer.get() == 0) || (! mGameControlServer->AgentConnect(static_cast<int>(agent))) ) { GetLog()->Normal() << "(SpadesServer) ERROR: cannot register agent " << "to the GameControlServer\n"; return false; } // schedule the first SpadesCreateSenseEvent SimTime time = static_cast<SimTime>(mNextInitialCreateSense); SpadesCreateSenseEvent* event = new SpadesCreateSenseEvent (time,agent); SimTime now = mSimEngine->getSimulationTime(); GetLog()->Normal() << "(SpadesServer) agentConnect (id " << agent << ") at simlation time " << now << ".\n" << "Initial CreateSenseEvent scheduled at " << time << "\n"; mNextInitialCreateSense += mOffsetCreateSense; mSimEngine->enqueueEvent(event); return true; } bool SpadesServer::agentDisappear(AgentID agent, AgentLostReason /*reason*/) { if (mGameControlServer.get() == 0) { return false; } return mGameControlServer->AgentDisappear(static_cast<int>(agent)); } void SpadesServer::notifyCommserverConnect(ServerID /*s*/) { } void SpadesServer::notifyCommserverDisconnect(ServerID /*s*/) { } void SpadesServer::UpdateCached() { GetScript()->GetVariable("Spades.TimePerStep", mTimePerStep); } |