00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00025 #include "SimpleGameClient.h"
00026
00027 Define_Module(SimpleGameClient);
00028
00029 void SimpleGameClient::initializeApp(int stage)
00030 {
00031
00032 if (stage != MIN_STAGE_APP) {
00033 return;
00034 }
00035
00036
00037 areaDimension = par("areaDimension");
00038 useScenery = par("useScenery");
00039 movementRate = par("movementRate");
00040 movementSpeed = par("movementSpeed");
00041 movementDelay= 1.0 / movementRate;
00042 AOIWidth = 0.0;
00043 logAOI = false;
00044 int groupSize = (int)par("groupSize");
00045 if(groupSize < 1) {
00046 groupSize = 1;
00047 }
00048 GeneratorType = par("movementGenerator").stdstringValue();
00049
00050 WATCH_MAP(Neighbors);
00051 WATCH_LIST(CollisionRect);
00052 WATCH(position);
00053 WATCH(GeneratorType);
00054 WATCH(overlayReady);
00055
00056 doRealworld = false;
00057 coordinator = check_and_cast<GlobalCoordinator*>(simulation.getModuleByPath("globalObserver.globalFunctions[0].function.coordinator"));
00058 scheduler = NULL;
00059 packetNotification = NULL;
00060
00061 frozen = false;
00062
00063 useHotspots = false;
00064 lastInHotspot = false;
00065 lastFarFromHotspot = false;
00066 lastAOImeasure = simTime();
00067 startAOI = 0;
00068 avgAOI = 0;
00069 hotspotTime = 0;
00070 avgHotspotAOI = 0;
00071 nonHotspotTime = 0;
00072 avgFarFromHotspotAOI = 0;
00073 farFromHotspotTime = 0;
00074
00075 CollisionList* listPtr = NULL;
00076 if(useScenery == true) {
00077 listPtr = &CollisionRect;
00078 }
00079
00080 double speed = SIMTIME_DBL(movementDelay) * movementSpeed;
00081 if(strcmp(GeneratorType.c_str(), "greatGathering") == 0) {
00082 if(debugOutput) {
00083 EV << "[SimpleGameClient::initializeApp() @ " << overlay->getThisNode().getIp()
00084 << " (" << overlay->getThisNode().getKey().toString(16) << ")]\n"
00085 << " SIMPLECLIENT: Movement generator: greatGathering"
00086 << endl;
00087 }
00088 Generator = new greatGathering(areaDimension, speed, &Neighbors, coordinator, listPtr);
00089 }
00090 else if(strcmp(GeneratorType.c_str(), "groupRoaming") == 0) {
00091 if(debugOutput) {
00092 EV << "[SimpleGameClient::initializeApp() @ " << overlay->getThisNode().getIp()
00093 << " (" << overlay->getThisNode().getKey().toString(16) << ")]\n"
00094 << " SIMPLECLIENT: Movement generator: groupRoaming"
00095 << endl;
00096 }
00097 Generator = new groupRoaming(areaDimension, speed, &Neighbors, coordinator, listPtr, groupSize);
00098 }
00099 else if(strcmp(GeneratorType.c_str(), "hotspotRoaming") == 0) {
00100 if(debugOutput) {
00101 EV << "[SimpleGameClient::initializeApp() @ " << overlay->getThisNode().getIp()
00102 << " (" << overlay->getThisNode().getKey().toString(16) << ")]\n"
00103 << " SIMPLECLIENT: Movement generator: hotspotRoaming"
00104 << endl;
00105 }
00106 Generator = new hotspotRoaming(areaDimension, speed, &Neighbors, coordinator, listPtr);
00107 useHotspots = true;
00108 }
00109 else if(strcmp(GeneratorType.c_str(), "traverseRoaming") == 0) {
00110 if(debugOutput) {
00111 EV << "[SimpleGameClient::initializeApp() @ " << overlay->getThisNode().getIp()
00112 << " (" << overlay->getThisNode().getKey().toString(16) << ")]\n"
00113 << " SIMPLECLIENT: Movement generator: traverseRoaming"
00114 << endl;
00115 }
00116 logAOI = true;
00117 Generator = new traverseRoaming(areaDimension, speed, &Neighbors, coordinator, listPtr);
00118 }
00119 else if(strcmp(GeneratorType.c_str(), "realWorldRoaming") == 0) {
00120 if(debugOutput) {
00121 EV << "[SimpleGameClient::initializeApp() @ " << overlay->getThisNode().getIp()
00122 << " (" << overlay->getThisNode().getKey().toString(16) << ")]\n"
00123 << " SIMPLECLIENT: Movement generator: realWorldRoaming"
00124 << endl;
00125 }
00126 Generator = new realWorldRoaming(areaDimension, movementSpeed, &Neighbors, coordinator, listPtr);
00127 mtu = par("mtu");
00128 packetNotification = new cMessage("packetNotification");
00129 scheduler = check_and_cast<RealtimeScheduler*>(simulation.getScheduler());
00130 scheduler->setInterfaceModule(this, packetNotification, &packetBuffer, mtu, true);
00131 appFd = INVALID_SOCKET;
00132 }
00133 else {
00134
00135 if(debugOutput) {
00136 if(strcmp(GeneratorType.c_str(), "randomRoaming") == 0) {
00137 EV << "[SimpleGameClient::initializeApp() @ " << overlay->getThisNode().getIp()
00138 << " (" << overlay->getThisNode().getKey().toString(16) << ")]\n"
00139 << " SIMPLECLIENT: Movement generator: randomRoaming"
00140 << endl;
00141 }
00142 else {
00143 EV << "[SimpleGameClient::initializeApp() @ " << overlay->getThisNode().getIp()
00144 << " (" << overlay->getThisNode().getKey().toString(16) << ")]\n"
00145 << " SIMPLECLIENT: Movement generator: <unknown>. Defaulting to: randomRoaming"
00146 << endl;
00147 }
00148 }
00149 Generator = new randomRoaming(areaDimension, speed, &Neighbors, coordinator, listPtr);
00150 }
00151
00152
00153 move_timer = new cMessage("move_timer");
00154 overlayReady = false;
00155 }
00156
00157 void SimpleGameClient::handleTimerEvent(cMessage* msg)
00158 {
00159 if(msg->isName("move_timer")) {
00160
00161 cancelEvent(move_timer);
00162 if(overlayReady) {
00163 scheduleAt(simTime() + movementDelay, msg);
00164 }
00165
00166 updatePosition();
00167 }
00168 else if(msg->isName("packetNotification")) {
00169 while(packetBuffer.size() > 0) {
00170
00171 RealtimeScheduler::PacketBufferEntry packet = *(packetBuffer.begin());
00172 packetBuffer.pop_front();
00173 switch (packet.func) {
00174 case RealtimeScheduler::PacketBufferEntry::PACKET_DATA: {
00175 if(packet.fd != appFd) {
00176 error("SimpleClient::handleMessage(): Received packet from unknown socket!");
00177 }
00178 handleRealworldPacket(packet.data, packet.length);
00179 } break;
00180 case RealtimeScheduler::PacketBufferEntry::PACKET_FD_NEW: {
00181 if(appFd != INVALID_SOCKET) {
00182 error("SimpleClient::handleMessage(): Multiple connections not supported yet!");
00183 }
00184 if (packet.addr != NULL) {
00185 delete packet.addr;
00186 packet.addr = NULL;
00187 }
00188 appFd = packet.fd;
00189 } break;
00190 case RealtimeScheduler::PacketBufferEntry::PACKET_FD_CLOSE: {
00191 if(packet.fd != appFd) {
00192 error("SimpleClient::handleMessage(): Trying to close unknown connection!");
00193 }
00194 appFd = INVALID_SOCKET;
00195 } break;
00196 default:
00197
00198 break;
00199 }
00200 delete packet.data;
00201 }
00202 }
00203 else if(msg->isName("Snowball landing")) {
00204 SCSnowTimer* snowTimer = check_and_cast<SCSnowTimer*>(msg);
00205 if(!frozen && position.distanceSqr(snowTimer->getPosition() / 32 ) < 2) {
00206
00207 frozen = true;
00208 cMessage* unfreeze = new cMessage("unfreeze me");
00209 scheduleAt(simTime() + 5, unfreeze);
00210
00211 GameAPIFrozenMessage* freeze = new GameAPIFrozenMessage("I'm frozen");
00212 freeze->setCommand(GAMEEVENT_FROZEN);
00213 freeze->setSrc(overlay->getThisNode());
00214 freeze->setThrower(snowTimer->getIp());
00215 freeze->setTimeSec(5);
00216 freeze->setTimeUsec(0);
00217 sendMessageToLowerTier(freeze);
00218
00219 if(doRealworld) {
00220 SCFrozenPacket scfreeze;
00221 scfreeze.packetType = SC_EV_FROZEN;
00222 scfreeze.ip = overlay->getThisNode().getIp().get4().getInt();
00223 scfreeze.source = snowTimer->getIp();
00224 scfreeze.time_sec = 5;
00225 scfreeze.time_usec = 0;
00226 int packetlen = sizeof(scfreeze);
00227 scheduler->sendBytes((const char*)&packetlen, sizeof(int), 0, 0, true, appFd);
00228 scheduler->sendBytes((const char*)&scfreeze, packetlen, 0, 0, true, appFd);
00229 }
00230 }
00231 delete msg;
00232 }
00233 else if(msg->isName("unfreeze me")) {
00234 frozen = false;
00235 delete msg;
00236 }
00237 }
00238
00239 void SimpleGameClient::handleLowerMessage(cMessage* msg)
00240 {
00241 if(dynamic_cast<GameAPIMessage*>(msg)) {
00242 GameAPIMessage* gameAPIMsg = check_and_cast<GameAPIMessage*>(msg);
00243 if(gameAPIMsg->getCommand() == MOVEMENT_REQUEST) {
00244 updatePosition();
00245 }
00246 else if(gameAPIMsg->getCommand() == NEIGHBOR_UPDATE) {
00247 GameAPIListMessage* gameAPIListMsg = check_and_cast<GameAPIListMessage*>(msg);
00248 updateNeighbors(gameAPIListMsg);
00249 }
00250 else if(gameAPIMsg->getCommand() == RESIZE_AOI) {
00251 GameAPIResizeAOIMessage* gameAPIResizeMsg = check_and_cast<GameAPIResizeAOIMessage*>(msg);
00252
00253
00254 if( startAOI != 0 )
00255 {
00256 RECORD_STATS(
00257 simtime_t elapsed = simTime() - lastAOImeasure;
00258 if( lastInHotspot ){
00259 avgHotspotAOI += AOIWidth*elapsed.dbl();
00260 hotspotTime += elapsed;
00261 } else {
00262 avgAOI += AOIWidth*elapsed.dbl();
00263 nonHotspotTime += elapsed;
00264 if( lastFarFromHotspot ){
00265 avgFarFromHotspotAOI += AOIWidth*elapsed.dbl();
00266 farFromHotspotTime += elapsed;
00267 }
00268 }
00269 );
00270 } else {
00271 startAOI = gameAPIResizeMsg->getAOIsize();
00272 }
00273 lastAOImeasure = simTime();
00274 if( useHotspots ){
00275 lastInHotspot = dynamic_cast<hotspotRoaming*>(Generator)->getDistanceFromHotspot() <= 0;
00276 lastFarFromHotspot = dynamic_cast<hotspotRoaming*>(Generator)->getDistanceFromHotspot() > startAOI;
00277 }
00278
00279 AOIWidth = gameAPIResizeMsg->getAOIsize();
00280 if( logAOI ){
00281 GlobalStatisticsAccess().get()->recordOutVector( "SimpleGameClient: AOI width", AOIWidth );
00282 }
00283 if(doRealworld) {
00284 SCAOIPacket packet;
00285 packet.packetType = SC_RESIZE_AOI;
00286 packet.AOI = AOIWidth;
00287 int packetlen = sizeof(SCAOIPacket);
00288 scheduler->sendBytes((const char*)&packetlen, sizeof(int), 0, 0, true, appFd);
00289 scheduler->sendBytes((const char*)&packet, packetlen, 0, 0, true, appFd);
00290 }
00291 }
00292 else if(gameAPIMsg->getCommand() == GAMEEVENT_CHAT) {
00293 if(doRealworld) {
00294 GameAPIChatMessage* chatMsg = check_and_cast<GameAPIChatMessage*>(msg);
00295 const char* msg = chatMsg->getMsg();
00296 int packetlen = sizeof(SCChatPacket) + strlen(msg) + 1;
00297 SCChatPacket* pack = (SCChatPacket*)malloc(packetlen);
00298 pack->packetType = SC_EV_CHAT;
00299 pack->ip = chatMsg->getSrc().getIp().get4().getInt();
00300 strcpy(pack->msg, msg);
00301 scheduler->sendBytes((const char*)&packetlen, sizeof(int), 0, 0, true, appFd);
00302 scheduler->sendBytes((const char*)pack, packetlen, 0, 0, true, appFd);
00303 free(pack);
00304 }
00305 }
00306 else if(gameAPIMsg->getCommand() == GAMEEVENT_SNOW) {
00307 GameAPISnowMessage* snowMsg = check_and_cast<GameAPISnowMessage*>(gameAPIMsg);
00308 if(doRealworld) {
00309 SCSnowPacket packet;
00310 packet.packetType = SC_EV_SNOWBALL;
00311 packet.ip = snowMsg->getSrc().getIp().get4().getInt();
00312 packet.startX = snowMsg->getStart().x;
00313 packet.startY = snowMsg->getStart().y;
00314 packet.endX = snowMsg->getEnd().x;
00315 packet.endY = snowMsg->getEnd().y;
00316 packet.time_sec = snowMsg->getTimeSec();
00317 packet.time_usec = snowMsg->getTimeUsec();
00318 int packetlen = sizeof(SCSnowPacket);
00319 scheduler->sendBytes((const char*)&packetlen, sizeof(int), 0, 0, true, appFd);
00320 scheduler->sendBytes((const char*)&packet, packetlen, 0, 0, true, appFd);
00321 }
00322 SCSnowTimer* snowTimer = new SCSnowTimer("Snowball landing");
00323 snowTimer->setPosition(snowMsg->getEnd());
00324 snowTimer->setIp(snowMsg->getSrc().getIp().get4().getInt());
00325 timeval snowTime;
00326 snowTime.tv_sec = snowMsg->getTimeSec();
00327 snowTime.tv_usec = snowMsg->getTimeUsec();
00328 simtime_t snow_t = snowTime.tv_sec + snowTime.tv_usec / 1000000.0;
00329 scheduleAt(simTime() + snow_t, snowTimer);
00330 }
00331 else if(gameAPIMsg->getCommand() == GAMEEVENT_FROZEN) {
00332 if(doRealworld) {
00333 GameAPIFrozenMessage* frozenMsg = check_and_cast<GameAPIFrozenMessage*>(gameAPIMsg);
00334 SCFrozenPacket scfreeze;
00335 scfreeze.packetType = SC_EV_FROZEN;
00336 scfreeze.ip = frozenMsg->getSrc().getIp().get4().getInt();
00337 scfreeze.source = frozenMsg->getThrower();
00338 scfreeze.time_sec = frozenMsg->getTimeSec();
00339 scfreeze.time_usec = frozenMsg->getTimeUsec();
00340 int packetlen = sizeof(scfreeze);
00341 scheduler->sendBytes((const char*)&packetlen, sizeof(int), 0, 0, true, appFd);
00342 scheduler->sendBytes((const char*)&scfreeze, packetlen, 0, 0, true, appFd);
00343 }
00344 }
00345 }
00346 delete msg;
00347 }
00348
00349 void SimpleGameClient::handleReadyMessage(CompReadyMessage* msg)
00350 {
00351
00352 if( getThisCompType() - msg->getComp() == 1 ){
00353 if(msg->getReady()) {
00354 overlayReady = true;
00355 if(!move_timer->isScheduled()) {
00356 scheduleAt(simTime() + movementDelay, move_timer);
00357 }
00358 }
00359 else {
00360 overlayReady = false;
00361 }
00362 }
00363 delete msg;
00364 }
00365
00366 void SimpleGameClient::handleRealworldPacket(char *buf, uint32_t len)
00367 {
00368 SCBasePacket *type = (SCBasePacket*)buf;
00369 if(type->packetType == SC_PARAM_REQUEST) {
00370 SCParamPacket packet;
00371 packet.packetType = SC_PARAM_RESPONSE;
00372 packet.speed = movementSpeed;
00373 packet.dimension = areaDimension;
00374 packet.AOI = AOIWidth;
00375 packet.delay = SIMTIME_DBL(movementDelay);
00376 packet.startX = position.x;
00377 packet.startY = position.y;
00378 packet.ip = thisNode.getIp().get4().getInt();
00379 packet.seed = coordinator->getSeed();
00380 int packetSize = sizeof(packet);
00381 scheduler->sendBytes((const char*)&packetSize, sizeof(int), 0, 0, true, appFd);
00382 scheduler->sendBytes((const char*)&packet, packetSize, 0, 0, true, appFd);
00383 doRealworld = true;
00384 }
00385 else if(type->packetType == SC_MOVE_INDICATION) {
00386 SCMovePacket *packet = (SCMovePacket*)type;
00387 Vector2D temp;
00388 temp.x = packet->posX;
00389 temp.y = packet->posY;
00390 dynamic_cast<realWorldRoaming*>(Generator)->setPosition(temp);
00391 }
00392 else if(type->packetType == SC_EV_CHAT) {
00393 SCChatPacket* packet = (SCChatPacket*)type;
00394 GameAPIChatMessage* chatMsg = new GameAPIChatMessage("ChatMsg");
00395 chatMsg->setCommand(GAMEEVENT_CHAT);
00396 chatMsg->setSrc(thisNode);
00397 chatMsg->setMsg(packet->msg);
00398 sendMessageToLowerTier(chatMsg);
00399 }
00400 else if(type->packetType == SC_EV_SNOWBALL) {
00401 SCSnowPacket* packet = (SCSnowPacket*)type;
00402 GameAPISnowMessage* snowMsg = new GameAPISnowMessage("Throw Snowball");
00403 snowMsg->setCommand(GAMEEVENT_SNOW);
00404 snowMsg->setSrc(thisNode);
00405 snowMsg->setStart(Vector2D(packet->startX, packet->startY));
00406 snowMsg->setEnd(Vector2D(packet->endX, packet->endY));
00407 snowMsg->setTimeSec(packet->time_sec);
00408 snowMsg->setTimeUsec(packet->time_usec);
00409 sendMessageToLowerTier(snowMsg);
00410 }
00411 }
00412
00413 void SimpleGameClient::updateNeighbors(GameAPIListMessage* sgcMsg)
00414 {
00415 unsigned int i;
00416
00417 if(doRealworld) {
00418 int packetSize;
00419
00420 SCRemovePacket removePacket;
00421 removePacket.packetType = SC_REMOVE_NEIGHBOR;
00422 packetSize = sizeof(removePacket);
00423
00424 for(i=0; i<sgcMsg->getRemoveNeighborArraySize(); ++i) {
00425 removePacket.ip = sgcMsg->getRemoveNeighbor(i).getIp().get4().getInt();
00426 scheduler->sendBytes((const char*)&packetSize, sizeof(int), 0, 0, true, appFd);
00427 scheduler->sendBytes((const char*)&removePacket, packetSize, 0, 0, true, appFd);
00428 }
00429
00430 SCAddPacket addPacket;
00431 addPacket.packetType = SC_ADD_NEIGHBOR;
00432 packetSize = sizeof(addPacket);
00433
00434 for(i=0; i<sgcMsg->getAddNeighborArraySize(); ++i) {
00435 addPacket.ip = sgcMsg->getAddNeighbor(i).getIp().get4().getInt();
00436 if( addPacket.ip == thisNode.getIp().get4().getInt() ) continue;
00437 addPacket.posX = sgcMsg->getNeighborPosition(i).x;
00438 addPacket.posY = sgcMsg->getNeighborPosition(i).y;
00439 scheduler->sendBytes((const char*)&packetSize, sizeof(int), 0, 0, true, appFd);
00440 scheduler->sendBytes((const char*)&addPacket, packetSize, 0, 0, true, appFd);
00441 }
00442 }
00443 for(i=0; i<sgcMsg->getRemoveNeighborArraySize(); ++i)
00444 Neighbors.erase(sgcMsg->getRemoveNeighbor(i));
00445
00446 for(i=0; i<sgcMsg->getAddNeighborArraySize(); ++i) {
00447 Vector2D newPos;
00448 newPos = sgcMsg->getNeighborPosition(i);
00449 itNeighbors = Neighbors.find(sgcMsg->getAddNeighbor(i));
00450 if(itNeighbors != Neighbors.end()) {
00451 Vector2D temp = newPos - itNeighbors->second.position;
00452 temp.normalize();
00453 itNeighbors->second.direction = temp;
00454 itNeighbors->second.position = newPos;
00455 }
00456 else {
00457 NeighborMapEntry entry;
00458 entry.position = newPos;
00459 Neighbors.insert(std::make_pair(sgcMsg->getAddNeighbor(i), entry));
00460 }
00461 }
00462 }
00463
00464 void SimpleGameClient::updatePosition()
00465 {
00466 if(!frozen) {
00467 Generator->move();
00468 }
00469 position = Generator->getPosition();
00470 GameAPIPositionMessage *posMsg = new GameAPIPositionMessage("MOVEMENT_INDICATION");
00471 posMsg->setCommand(MOVEMENT_INDICATION);
00472 posMsg->setPosition(position);
00473 sendMessageToLowerTier(posMsg);
00474 }
00475
00476 void SimpleGameClient::finishApp()
00477 {
00478 if (nonHotspotTime >= GlobalStatistics::MIN_MEASURED) {
00479 globalStatistics->addStdDev("SimpleGameClient: average non-hotspot AOI",
00480 avgAOI / nonHotspotTime);
00481 }
00482 if (farFromHotspotTime >= GlobalStatistics::MIN_MEASURED) {
00483 globalStatistics->addStdDev("SimpleGameClient: average far-from-hotspot AOI",
00484 avgFarFromHotspotAOI / farFromHotspotTime);
00485 }
00486 if (hotspotTime >= GlobalStatistics::MIN_MEASURED) {
00487 globalStatistics->addStdDev("SimpleGameClient: average hotspot AOI",
00488 avgHotspotAOI / hotspotTime);
00489 }
00490 }
00491
00492 SimpleGameClient::~SimpleGameClient()
00493 {
00494
00495 cancelAndDelete(move_timer);
00496 cancelAndDelete(packetNotification);
00497 delete Generator;
00498 }