SimMud.cc

Go to the documentation of this file.
00001 //
00002 // Copyright (C) 2006 Institut fuer Telematik, Universitaet Karlsruhe (TH)
00003 //
00004 // This program is free software; you can redistribute it and/or
00005 // modify it under the terms of the GNU General Public License
00006 // as published by the Free Software Foundation; either version 2
00007 // of the License, or (at your option) any later version.
00008 //
00009 // This program is distributed in the hope that it will be useful,
00010 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 // GNU General Public License for more details.
00013 //
00014 // You should have received a copy of the GNU General Public License
00015 // along with this program; if not, write to the Free Software
00016 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00017 //
00018 
00024 #include "SimMud.h"
00025 #include "ScribeMessage_m.h"
00026 #include <limits.h>
00027 #include <GlobalStatistics.h>
00028 
00029 Define_Module(SimMud);
00030 
00031 using namespace std;
00032 
00033 SimMud::SimMud()
00034 {
00035     currentRegionX = currentRegionY = INT_MIN;
00036     currentRegionID = OverlayKey::UNSPECIFIED_KEY;
00037     playerTimer = new cMessage("playerTimeout");
00038 }
00039 
00040 SimMud::~SimMud()
00041 {
00042     cancelAndDelete(playerTimer);
00043 }
00044 
00045 void SimMud::finishApp()
00046 {
00047     simtime_t time = globalStatistics->calcMeasuredLifetime(creationTime);
00048     if (time < GlobalStatistics::MIN_MEASURED) return;
00049 
00050     globalStatistics->addStdDev("SimMUD: Lost or too long delayed MoveLists/s",
00051                                 lostMovementLists / time);
00052     globalStatistics->addStdDev("SimMUD: Received valid MoveLists/s",
00053                                 receivedMovementLists / time);
00054 }
00055 
00056 void SimMud::initializeApp(int stage)
00057 {
00058     if( stage != (numInitStages()-1)) {
00059         return;
00060     }
00061 
00062     // FIXME: areaDimension is not used consistently between all overlays!
00063     fieldSize = par("areaDimension");
00064     numSubspaces = par("numSubspaces");
00065     regionSize = fieldSize / numSubspaces;
00066     playerTimeout = par("playerTimeout");
00067 
00068     receivedMovementLists = 0;
00069     lostMovementLists = 0;
00070 
00071     maxMoveDelay = par("maxMoveDelay");
00072     AOIWidth = par("AOIWidth");
00073 
00074     WATCH(currentRegionX);
00075     WATCH(currentRegionY);
00076     WATCH(currentRegionID);
00077 //    WATCH_MAP( playerMap );
00078 }
00079 
00080 bool SimMud::handleRpcCall( BaseCallMessage* msg )
00081 {
00082 //    RPC_SWITCH_START(msg);
00083 //    RPC_SWITCH_END( );
00084 //    return RPC_HANDLED;
00085       return false;
00086 }
00087 
00088 void SimMud::handleRpcResponse( BaseResponseMessage* msg,
00089                                 cPolymorphic* context,
00090                                 int rpcId, simtime_t rtt )
00091 {
00092 //    RPC_SWITCH_START(msg);
00093 //    RPC_SWITCH_END( );
00094 }
00095 
00096 void SimMud::handleTimerEvent( cMessage *msg )
00097 {
00098     if( msg == playerTimer ) {
00099         // Check if any player didn't send any updates since last check
00100         map<NodeHandle, PlayerInfo>::iterator it;
00101         list<NodeHandle> erasePlayers;
00102         for( it = playerMap.begin(); it != playerMap.end(); ++it ) {
00103             if( it->second.update == false ) {
00104                 erasePlayers.push_back( it->first );
00105             }
00106             it->second.update = false;
00107         }
00108         for( list<NodeHandle>::iterator it = erasePlayers.begin(); it != erasePlayers.end(); ++it) {
00109             // Delete all neighbors that didn't update (and inform app)
00110             GameAPIListMessage *scMsg = new GameAPIListMessage("NEIGHBOR_UPDATE");
00111             scMsg->setCommand(NEIGHBOR_UPDATE);
00112             scMsg->setRemoveNeighborArraySize(1);
00113             scMsg->setRemoveNeighbor(0, *it);
00114             send(scMsg, "to_upperTier");
00115 
00116             playerMap.erase( *it );
00117         }
00118         erasePlayers.clear();
00119 
00120         scheduleAt( simTime() + playerTimeout, msg );
00121     }
00122 }
00123 
00124 void SimMud::handleLowerMessage( cMessage *msg )
00125 {
00126     if (ALMMulticastMessage* mcastMsg =
00127             dynamic_cast<ALMMulticastMessage*>(msg) ){
00128 
00129         cMessage* innerMsg = mcastMsg->decapsulate();
00130         SimMudMoveMessage* moveMsg = NULL;
00131         if( innerMsg ) {
00132                 moveMsg = dynamic_cast<SimMudMoveMessage*>(innerMsg);
00133         }
00134         if( moveMsg ) {
00135             handleOtherPlayerMove( moveMsg );
00136         }
00137         delete innerMsg;
00138         delete mcastMsg;
00139     }
00140 }
00141 
00142 void SimMud::handleReadyMessage( CompReadyMessage *msg )
00143 {
00144     // process only ready messages from the tier below
00145     if( getThisCompType() - msg->getComp() == 1 ){
00146         if( msg->getReady() ) {
00147             // TODO/FIXME: use overlay->sendMessageToAllComp(msg, getThisCompType())?
00148             msg->setComp(getThisCompType());
00149             send(msg, "to_upperTier");
00150             // also send AOI size to SimpleGameClient
00151             GameAPIResizeAOIMessage* gameMsg = new GameAPIResizeAOIMessage("RESIZE_AOI");
00152             gameMsg->setCommand(RESIZE_AOI);
00153             gameMsg->setAOIsize(AOIWidth);
00154             send(gameMsg, "to_upperTier");
00155 
00156             if( playerTimeout > 0 ) {
00157                 cancelEvent( playerTimer );
00158                 scheduleAt( simTime() + playerTimeout, playerTimer );
00159             }
00160         }
00161     } else {
00162         delete msg;
00163     }
00164 }
00165 
00166 void SimMud::handleUpperMessage( cMessage *msg )
00167 {
00168     if( GameAPIPositionMessage* moveMsg =
00169         dynamic_cast<GameAPIPositionMessage*>(msg) ) {
00170         handleMove( moveMsg );
00171         delete msg;
00172     }
00173 }
00174 
00175 void SimMud::handleMove( GameAPIPositionMessage* msg )
00176 {
00177     if( (int) (msg->getPosition().x/regionSize) != currentRegionX ||
00178             (int) (msg->getPosition().y/regionSize) != currentRegionY ) {
00179         // New position is outside of current region; change currentRegion
00180 
00181         // get region ID
00182         currentRegionX = (int) (msg->getPosition().x/regionSize);
00183         currentRegionY = (int) (msg->getPosition().y/regionSize);
00184         std::stringstream regionstr;
00185         regionstr << currentRegionX << ":" << currentRegionY;
00186         OverlayKey region = OverlayKey::sha1( BinaryValue(regionstr.str() ));
00187         currentRegionID = region;
00188     }
00189 
00190     set<OverlayKey> expectedRegions;
00191     set<OverlayKey> allowedRegions;
00192     int minX = (int) ((msg->getPosition().x - AOIWidth)/regionSize);
00193     if( minX < 0 ) minX = 0;
00194     int maxX = (int) ((msg->getPosition().x + AOIWidth)/regionSize);
00195     if( maxX >= numSubspaces ) maxX = numSubspaces -1;
00196     int minY = (int) ((msg->getPosition().y - AOIWidth)/regionSize);
00197     if( minY < 0 ) minY = 0;
00198     int maxY = (int) ((msg->getPosition().y + AOIWidth)/regionSize);
00199     if( maxY >= numSubspaces ) maxY = numSubspaces -1;
00200 
00201     // FIXME: make parameter: unsubscription size
00202     int minUnsubX = (int) ((msg->getPosition().x - 1.5*AOIWidth)/regionSize);
00203     if( minUnsubX < 0 ) minUnsubX = 0;
00204     int maxUnsubX = (int) ((msg->getPosition().x + 1.5*AOIWidth)/regionSize);
00205     if( maxUnsubX >= numSubspaces ) maxUnsubX = numSubspaces -1;
00206     int minUnsubY = (int) ((msg->getPosition().y - 1.5*AOIWidth)/regionSize);
00207     if( minUnsubY < 0 ) minUnsubY = 0;
00208     int maxUnsubY = (int) ((msg->getPosition().y + 1.5+AOIWidth)/regionSize);
00209     if( maxUnsubY >= numSubspaces ) maxUnsubY = numSubspaces -1;
00210 
00211     for( int x = minUnsubX; x <= maxUnsubX; ++x ){
00212         for( int y = minUnsubY; y <= maxUnsubY; ++y ){
00213             std::stringstream regionstr;
00214             regionstr << x << ":" << y;
00215             if( x >= minX && x <=maxX && y >= minY && y <= maxY ){
00216                 expectedRegions.insert( OverlayKey::sha1( BinaryValue(regionstr.str() )));
00217             }
00218             allowedRegions.insert( OverlayKey::sha1( BinaryValue(regionstr.str() )));
00219         }
00220     }
00221 
00222     set<OverlayKey>::iterator subIt = subscribedRegions.begin();
00223     while( subIt != subscribedRegions.end() ){
00224 
00225         expectedRegions.erase( *subIt );
00226 
00227         // unsubscribe region if to far away
00228         if( allowedRegions.find( *subIt ) == allowedRegions.end() ){
00229             // Inform other players about region leave
00230             SimMudMoveMessage* moveMsg = new SimMudMoveMessage("MOVE/LEAVE_REGION");
00231             moveMsg->setSrc( overlay->getThisNode() );
00232             moveMsg->setPosX( msg->getPosition().x );
00233             moveMsg->setPosY( msg->getPosition().y );
00234             moveMsg->setTimestamp( simTime() );
00235             moveMsg->setLeaveRegion( true );
00236             ALMMulticastMessage* mcastMsg = new ALMMulticastMessage("MOVE/LEAVE_REGION");
00237             mcastMsg->setGroupId(*subIt);
00238             mcastMsg->encapsulate( moveMsg );
00239 
00240             send(mcastMsg, "to_lowerTier");
00241 
00242              // leave old region's multicastGroup
00243             ALMLeaveMessage* leaveMsg = new ALMLeaveMessage("LEAVE_REGION_GROUP");
00244             leaveMsg->setGroupId(*subIt);
00245             send(leaveMsg, "to_lowerTier");
00246             // TODO: leave old simMud region
00247 
00248            // Erase subspace from subscribedList and increase iterator
00249             subscribedRegions.erase( subIt++ );
00250         } else {
00251             ++subIt;
00252         }
00253     }
00254 
00255     // if any "near" region is not yet subscribed, subscribe
00256     for( set<OverlayKey>::iterator regionIt = expectedRegions.begin(); regionIt != expectedRegions.end(); ++regionIt ){
00257         // join region's multicast group
00258         ALMSubscribeMessage* subMsg = new ALMSubscribeMessage;
00259         subMsg->setGroupId(*regionIt);
00260         send( subMsg, "to_lowerTier" );
00261 
00262         subscribedRegions.insert( *regionIt );
00263         // TODO: join simMud region
00264     }
00265 
00266     // publish movement
00267     SimMudMoveMessage* moveMsg = new SimMudMoveMessage("MOVE");
00268     moveMsg->setSrc( overlay->getThisNode() );
00269     moveMsg->setPosX( msg->getPosition().x );
00270     moveMsg->setPosY( msg->getPosition().y );
00271     moveMsg->setTimestamp( simTime() );
00272     moveMsg->setBitLength( SIMMUD_MOVE_L( moveMsg ));
00273     ALMMulticastMessage* mcastMsg = new ALMMulticastMessage("MOVE");
00274     mcastMsg->setGroupId(currentRegionID);
00275     mcastMsg->encapsulate( moveMsg );
00276 
00277     send(mcastMsg, "to_lowerTier");
00278 }
00279 
00280 void SimMud::handleOtherPlayerMove( SimMudMoveMessage* msg )
00281 {
00282     GameAPIListMessage *scMsg = new GameAPIListMessage("NEIGHBOR_UPDATE");
00283     scMsg->setCommand(NEIGHBOR_UPDATE);
00284 
00285     NodeHandle& src = msg->getSrc();
00286     RECORD_STATS(
00287             if( msg->getTimestamp() < simTime() - maxMoveDelay ){
00288                 ++lostMovementLists;
00289                 globalStatistics->addStdDev("SimMUD: LOST MOVE Delay",
00290                     SIMTIME_DBL(simTime() - msg->getTimestamp()) );
00291             } else {
00292                 ++receivedMovementLists;
00293             }
00294 
00295             if( src != overlay->getThisNode() ){
00296                 globalStatistics->addStdDev("SimMUD: MOVE Delay",
00297                     SIMTIME_DBL(simTime() - msg->getTimestamp()) );
00298             }
00299             );
00300 
00301     if( msg->getLeaveRegion() ) {
00302         // Player leaves region
00303         scMsg->setRemoveNeighborArraySize(1);
00304         scMsg->setRemoveNeighbor(0, src);
00305         playerMap.erase( src );
00306 
00307     } else {
00308         PlayerInfo player;
00309         player.pos = Vector2D( msg->getPosX(), msg->getPosY() );
00310         player.update = true;
00311 
00312         pair< map<NodeHandle, PlayerInfo>::iterator, bool> inserter =
00313             playerMap.insert( make_pair(src, player) );
00314 
00315         /*    if( inserter.second ) {
00316             // new player
00317 
00318         } else {
00319             // move player
00320         }*/
00321 
00322         // Ordinary move
00323         scMsg->setAddNeighborArraySize(1);
00324         scMsg->setNeighborPositionArraySize(1);
00325         scMsg->setAddNeighbor(0, src);
00326         scMsg->setNeighborPosition(0, Vector2D(msg->getPosX(), msg->getPosY()) );
00327     }
00328     send(scMsg, "to_upperTier");
00329 
00330 }
00331 
Generated on Wed May 26 16:21:15 2010 for OverSim by  doxygen 1.6.3