SimMud.cc
Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
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
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
00078 }
00079
00080 bool SimMud::handleRpcCall( BaseCallMessage* msg )
00081 {
00082
00083
00084
00085 return false;
00086 }
00087
00088 void SimMud::handleRpcResponse( BaseResponseMessage* msg,
00089 cPolymorphic* context,
00090 int rpcId, simtime_t rtt )
00091 {
00092
00093
00094 }
00095
00096 void SimMud::handleTimerEvent( cMessage *msg )
00097 {
00098 if( msg == playerTimer ) {
00099
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
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
00145 if( getThisCompType() - msg->getComp() == 1 ){
00146 if( msg->getReady() ) {
00147
00148 msg->setComp(getThisCompType());
00149 send(msg, "to_upperTier");
00150
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
00180
00181
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
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
00228 if( allowedRegions.find( *subIt ) == allowedRegions.end() ){
00229
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
00243 ALMLeaveMessage* leaveMsg = new ALMLeaveMessage("LEAVE_REGION_GROUP");
00244 leaveMsg->setGroupId(*subIt);
00245 send(leaveMsg, "to_lowerTier");
00246
00247
00248
00249 subscribedRegions.erase( subIt++ );
00250 } else {
00251 ++subIt;
00252 }
00253 }
00254
00255
00256 for( set<OverlayKey>::iterator regionIt = expectedRegions.begin(); regionIt != expectedRegions.end(); ++regionIt ){
00257
00258 ALMSubscribeMessage* subMsg = new ALMSubscribeMessage;
00259 subMsg->setGroupId(*regionIt);
00260 send( subMsg, "to_lowerTier" );
00261
00262 subscribedRegions.insert( *regionIt );
00263
00264 }
00265
00266
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
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
00316
00317
00318
00319
00320
00321
00322
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