OverSim
SimpleGameClient.cc
Go to the documentation of this file.
1 //
2 // Copyright (C) 2006 Institut fuer Telematik, Universitaet Karlsruhe (TH)
3 //
4 // This program is free software; you can redistribute it and/or
5 // modify it under the terms of the GNU General Public License
6 // as published by the Free Software Foundation; either version 2
7 // of the License, or (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program; if not, write to the Free Software
16 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 //
18 
25 #include "SimpleGameClient.h"
26 
28 
30 {
31  // all initialization is done in the first stage
32  if (stage != MIN_STAGE_APP) {
33  return;
34  }
35 
36  // fetch parameters
37  areaDimension = par("areaDimension");
38  useScenery = par("useScenery");
39  movementRate = par("movementRate");
40  movementSpeed = par("movementSpeed");
42  AOIWidth = 0.0;
43  logAOI = false;
44  int groupSize = (int)par("groupSize");
45  if(groupSize < 1) {
46  groupSize = 1;
47  }
48  GeneratorType = par("movementGenerator").stdstringValue();
49 
50  WATCH_MAP(Neighbors);
51  WATCH_LIST(CollisionRect);
52  WATCH(position);
53  WATCH(GeneratorType);
54  WATCH(overlayReady);
55 
56  doRealworld = false;
57  coordinator = check_and_cast<GlobalCoordinator*>(simulation.getModuleByPath("globalObserver.globalFunctions[0].function.coordinator"));
58  scheduler = NULL;
59  packetNotification = NULL;
60 
61  frozen = false;
62 
63  useHotspots = false;
64  lastInHotspot = false;
65  lastFarFromHotspot = false;
66  lastAOImeasure = simTime();
67  startAOI = 0;
68  avgAOI = 0;
69  hotspotTime = 0;
70  avgHotspotAOI = 0;
71  nonHotspotTime = 0;
74 
75  CollisionList* listPtr = NULL;
76  if(useScenery == true) {
77  listPtr = &CollisionRect;
78  }
79 
80  double speed = SIMTIME_DBL(movementDelay) * movementSpeed;
81  if(strcmp(GeneratorType.c_str(), "greatGathering") == 0) {
82  if(debugOutput) {
83  EV << "[SimpleGameClient::initializeApp() @ " << overlay->getThisNode().getIp()
84  << " (" << overlay->getThisNode().getKey().toString(16) << ")]\n"
85  << " SIMPLECLIENT: Movement generator: greatGathering"
86  << endl;
87  }
89  }
90  else if(strcmp(GeneratorType.c_str(), "groupRoaming") == 0) {
91  if(debugOutput) {
92  EV << "[SimpleGameClient::initializeApp() @ " << overlay->getThisNode().getIp()
93  << " (" << overlay->getThisNode().getKey().toString(16) << ")]\n"
94  << " SIMPLECLIENT: Movement generator: groupRoaming"
95  << endl;
96  }
97  Generator = new groupRoaming(areaDimension, speed, &Neighbors, coordinator, listPtr, groupSize);
98  }
99  else if(strcmp(GeneratorType.c_str(), "hotspotRoaming") == 0) {
100  if(debugOutput) {
101  EV << "[SimpleGameClient::initializeApp() @ " << overlay->getThisNode().getIp()
102  << " (" << overlay->getThisNode().getKey().toString(16) << ")]\n"
103  << " SIMPLECLIENT: Movement generator: hotspotRoaming"
104  << endl;
105  }
106  Generator = new hotspotRoaming(areaDimension, speed, &Neighbors, coordinator, listPtr);
107  useHotspots = true;
108  }
109  else if(strcmp(GeneratorType.c_str(), "traverseRoaming") == 0) {
110  if(debugOutput) {
111  EV << "[SimpleGameClient::initializeApp() @ " << overlay->getThisNode().getIp()
112  << " (" << overlay->getThisNode().getKey().toString(16) << ")]\n"
113  << " SIMPLECLIENT: Movement generator: traverseRoaming"
114  << endl;
115  }
116  logAOI = true;
117  Generator = new traverseRoaming(areaDimension, speed, &Neighbors, coordinator, listPtr);
118  }
119  else if(strcmp(GeneratorType.c_str(), "realWorldRoaming") == 0) {
120  if(debugOutput) {
121  EV << "[SimpleGameClient::initializeApp() @ " << overlay->getThisNode().getIp()
122  << " (" << overlay->getThisNode().getKey().toString(16) << ")]\n"
123  << " SIMPLECLIENT: Movement generator: realWorldRoaming"
124  << endl;
125  }
127  mtu = par("mtu");
128  packetNotification = new cMessage("packetNotification");
129  scheduler = check_and_cast<RealtimeScheduler*>(simulation.getScheduler());
130  scheduler->setInterfaceModule(this, packetNotification, &packetBuffer, mtu, true);
131  appFd = INVALID_SOCKET;
132  }
133  else {
134  // debug output
135  if(debugOutput) {
136  if(strcmp(GeneratorType.c_str(), "randomRoaming") == 0) {
137  EV << "[SimpleGameClient::initializeApp() @ " << overlay->getThisNode().getIp()
138  << " (" << overlay->getThisNode().getKey().toString(16) << ")]\n"
139  << " SIMPLECLIENT: Movement generator: randomRoaming"
140  << endl;
141  }
142  else {
143  EV << "[SimpleGameClient::initializeApp() @ " << overlay->getThisNode().getIp()
144  << " (" << overlay->getThisNode().getKey().toString(16) << ")]\n"
145  << " SIMPLECLIENT: Movement generator: <unknown>. Defaulting to: randomRoaming"
146  << endl;
147  }
148  }
149  Generator = new randomRoaming(areaDimension, speed, &Neighbors, coordinator, listPtr);
150  }
151 
152  // self-messages
153  move_timer = new cMessage("move_timer");
154  overlayReady = false;
155 }
156 
158 {
159  if(msg->isName("move_timer")) {
160  //reset timer
161  cancelEvent(move_timer);
162  if(overlayReady) {
163  scheduleAt(simTime() + movementDelay, msg);
164  }
165  // handle event
166  updatePosition();
167  }
168  else if(msg->isName("packetNotification")) {
169  while(packetBuffer.size() > 0) {
170  // get packet from buffer and parse it
171  PacketBufferEntry packet = *(packetBuffer.begin());
172  packetBuffer.pop_front();
173  switch (packet.func) {
175  if(packet.fd != appFd) {
176  error("SimpleClient::handleMessage(): Received packet from unknown socket!");
177  }
178  handleRealworldPacket(packet.data, packet.length);
179  } break;
181  if(appFd != INVALID_SOCKET) {
182  error("SimpleClient::handleMessage(): Multiple connections not supported yet!");
183  }
184  if (packet.addr != NULL) {
185  delete packet.addr;
186  packet.addr = NULL;
187  }
188  appFd = packet.fd;
189  } break;
191  if(packet.fd != appFd) {
192  error("SimpleClient::handleMessage(): Trying to close unknown connection!");
193  }
194  appFd = INVALID_SOCKET;
195  } break;
196  default:
197  // Unknown socket function, ignore
198  break;
199  }
200  delete packet.data;
201  }
202  }
203  else if(msg->isName("Snowball landing")) {
204  SCSnowTimer* snowTimer = check_and_cast<SCSnowTimer*>(msg);
205  if(!frozen && position.distanceSqr(snowTimer->getPosition() / 32 ) < 2) {
206  // freeze me!
207  frozen = true;
208  cMessage* unfreeze = new cMessage("unfreeze me");
209  scheduleAt(simTime() + 5, unfreeze);
210 
211  GameAPIFrozenMessage* freeze = new GameAPIFrozenMessage("I'm frozen");
212  freeze->setCommand(GAMEEVENT_FROZEN);
213  freeze->setSrc(overlay->getThisNode());
214  freeze->setThrower(snowTimer->getIp());
215  freeze->setTimeSec(5);
216  freeze->setTimeUsec(0);
217  sendMessageToLowerTier(freeze);
218 
219  if(doRealworld) {
220  SCFrozenPacket scfreeze;
221  scfreeze.packetType = SC_EV_FROZEN;
222  scfreeze.ip = overlay->getThisNode().getIp().get4().getInt();
223  scfreeze.source = snowTimer->getIp();
224  scfreeze.time_sec = 5;
225  scfreeze.time_usec = 0;
226  int packetlen = sizeof(scfreeze);
227  scheduler->sendBytes((const char*)&packetlen, sizeof(int), 0, 0, true, appFd);
228  scheduler->sendBytes((const char*)&scfreeze, packetlen, 0, 0, true, appFd);
229  }
230  }
231  delete msg;
232  }
233  else if(msg->isName("unfreeze me")) {
234  frozen = false;
235  delete msg;
236  }
237 }
238 
240 {
241  if(dynamic_cast<GameAPIMessage*>(msg)) {
242  GameAPIMessage* gameAPIMsg = check_and_cast<GameAPIMessage*>(msg);
243  if(gameAPIMsg->getCommand() == MOVEMENT_REQUEST) {
244  updatePosition();
245  }
246  else if(gameAPIMsg->getCommand() == NEIGHBOR_UPDATE) {
247  GameAPIListMessage* gameAPIListMsg = check_and_cast<GameAPIListMessage*>(msg);
248  updateNeighbors(gameAPIListMsg);
249  }
250  else if(gameAPIMsg->getCommand() == RESIZE_AOI) {
251  GameAPIResizeAOIMessage* gameAPIResizeMsg = check_and_cast<GameAPIResizeAOIMessage*>(msg);
252 
253  // Measure average AOI sizes
254  if( startAOI != 0 )
255  {
256  RECORD_STATS(
257  simtime_t elapsed = simTime() - lastAOImeasure;
258  if( lastInHotspot ){
259  avgHotspotAOI += AOIWidth*elapsed.dbl();
260  hotspotTime += elapsed;
261  } else {
262  avgAOI += AOIWidth*elapsed.dbl();
263  nonHotspotTime += elapsed;
264  if( lastFarFromHotspot ){
265  avgFarFromHotspotAOI += AOIWidth*elapsed.dbl();
266  farFromHotspotTime += elapsed;
267  }
268  }
269  );
270  } else {
271  startAOI = gameAPIResizeMsg->getAOIsize();
272  }
273  lastAOImeasure = simTime();
274  if( useHotspots ){
275  lastInHotspot = dynamic_cast<hotspotRoaming*>(Generator)->getDistanceFromHotspot() <= 0;
276  lastFarFromHotspot = dynamic_cast<hotspotRoaming*>(Generator)->getDistanceFromHotspot() > startAOI;
277  }
278 
279  AOIWidth = gameAPIResizeMsg->getAOIsize();
280  if( logAOI ){
281  GlobalStatisticsAccess().get()->recordOutVector( "SimpleGameClient: AOI width", AOIWidth );
282  }
283  if(doRealworld) {
284  SCAOIPacket packet;
285  packet.packetType = SC_RESIZE_AOI;
286  packet.AOI = AOIWidth;
287  int packetlen = sizeof(SCAOIPacket);
288  scheduler->sendBytes((const char*)&packetlen, sizeof(int), 0, 0, true, appFd);
289  scheduler->sendBytes((const char*)&packet, packetlen, 0, 0, true, appFd);
290  }
291  }
292  else if(gameAPIMsg->getCommand() == GAMEEVENT_CHAT) {
293  if(doRealworld) {
294  GameAPIChatMessage* chatMsg = check_and_cast<GameAPIChatMessage*>(msg);
295  const char* msg = chatMsg->getMsg();
296  int packetlen = sizeof(SCChatPacket) + strlen(msg) + 1;
297  SCChatPacket* pack = (SCChatPacket*)malloc(packetlen);
298  pack->packetType = SC_EV_CHAT;
299  pack->ip = chatMsg->getSrc().getIp().get4().getInt();
300  strcpy(pack->msg, msg);
301  scheduler->sendBytes((const char*)&packetlen, sizeof(int), 0, 0, true, appFd);
302  scheduler->sendBytes((const char*)pack, packetlen, 0, 0, true, appFd);
303  free(pack);
304  }
305  }
306  else if(gameAPIMsg->getCommand() == GAMEEVENT_SNOW) {
307  GameAPISnowMessage* snowMsg = check_and_cast<GameAPISnowMessage*>(gameAPIMsg);
308  if(doRealworld) {
309  SCSnowPacket packet;
310  packet.packetType = SC_EV_SNOWBALL;
311  packet.ip = snowMsg->getSrc().getIp().get4().getInt();
312  packet.startX = snowMsg->getStart().x;
313  packet.startY = snowMsg->getStart().y;
314  packet.endX = snowMsg->getEnd().x;
315  packet.endY = snowMsg->getEnd().y;
316  packet.time_sec = snowMsg->getTimeSec();
317  packet.time_usec = snowMsg->getTimeUsec();
318  int packetlen = sizeof(SCSnowPacket);
319  scheduler->sendBytes((const char*)&packetlen, sizeof(int), 0, 0, true, appFd);
320  scheduler->sendBytes((const char*)&packet, packetlen, 0, 0, true, appFd);
321  }
322  SCSnowTimer* snowTimer = new SCSnowTimer("Snowball landing");
323  snowTimer->setPosition(snowMsg->getEnd());
324  snowTimer->setIp(snowMsg->getSrc().getIp().get4().getInt());
325  timeval snowTime;
326  snowTime.tv_sec = snowMsg->getTimeSec();
327  snowTime.tv_usec = snowMsg->getTimeUsec();
328  simtime_t snow_t = snowTime.tv_sec + snowTime.tv_usec / 1000000.0;
329  scheduleAt(simTime() + snow_t, snowTimer);
330  }
331  else if(gameAPIMsg->getCommand() == GAMEEVENT_FROZEN) {
332  if(doRealworld) {
333  GameAPIFrozenMessage* frozenMsg = check_and_cast<GameAPIFrozenMessage*>(gameAPIMsg);
334  SCFrozenPacket scfreeze;
335  scfreeze.packetType = SC_EV_FROZEN;
336  scfreeze.ip = frozenMsg->getSrc().getIp().get4().getInt();
337  scfreeze.source = frozenMsg->getThrower();
338  scfreeze.time_sec = frozenMsg->getTimeSec();
339  scfreeze.time_usec = frozenMsg->getTimeUsec();
340  int packetlen = sizeof(scfreeze);
341  scheduler->sendBytes((const char*)&packetlen, sizeof(int), 0, 0, true, appFd);
342  scheduler->sendBytes((const char*)&scfreeze, packetlen, 0, 0, true, appFd);
343  }
344  }
345  }
346  delete msg;
347 }
348 
350 {
351  // process only ready messages from the tier below
352  if( getThisCompType() - msg->getComp() == 1 ){
353  if(msg->getReady()) {
354  overlayReady = true;
355  if(!move_timer->isScheduled()) {
356  scheduleAt(simTime() + movementDelay, move_timer);
357  }
358  }
359  else {
360  overlayReady = false;
361  }
362  }
363  delete msg;
364 }
365 
366 void SimpleGameClient::handleRealworldPacket(char *buf, uint32_t len)
367 {
368  SCBasePacket *type = (SCBasePacket*)buf;
369  if(type->packetType == SC_PARAM_REQUEST) {
370  SCParamPacket packet;
371  packet.packetType = SC_PARAM_RESPONSE;
372  packet.speed = movementSpeed;
373  packet.dimension = areaDimension;
374  packet.AOI = AOIWidth;
375  packet.delay = SIMTIME_DBL(movementDelay);
376  packet.startX = position.x;
377  packet.startY = position.y;
378  packet.ip = thisNode.getIp().get4().getInt();
379  packet.seed = coordinator->getSeed();
380  int packetSize = sizeof(packet);
381  scheduler->sendBytes((const char*)&packetSize, sizeof(int), 0, 0, true, appFd);
382  scheduler->sendBytes((const char*)&packet, packetSize, 0, 0, true, appFd);
383  doRealworld = true;
384  }
385  else if(type->packetType == SC_MOVE_INDICATION) {
386  SCMovePacket *packet = (SCMovePacket*)type;
387  Vector2D temp;
388  temp.x = packet->posX;
389  temp.y = packet->posY;
390  dynamic_cast<realWorldRoaming*>(Generator)->setPosition(temp);
391  }
392  else if(type->packetType == SC_EV_CHAT) {
393  SCChatPacket* packet = (SCChatPacket*)type;
394  GameAPIChatMessage* chatMsg = new GameAPIChatMessage("ChatMsg");
395  chatMsg->setCommand(GAMEEVENT_CHAT);
396  chatMsg->setSrc(thisNode);
397  chatMsg->setMsg(packet->msg);
398  sendMessageToLowerTier(chatMsg);
399  }
400  else if(type->packetType == SC_EV_SNOWBALL) {
401  SCSnowPacket* packet = (SCSnowPacket*)type;
402  GameAPISnowMessage* snowMsg = new GameAPISnowMessage("Throw Snowball");
403  snowMsg->setCommand(GAMEEVENT_SNOW);
404  snowMsg->setSrc(thisNode);
405  snowMsg->setStart(Vector2D(packet->startX, packet->startY));
406  snowMsg->setEnd(Vector2D(packet->endX, packet->endY));
407  snowMsg->setTimeSec(packet->time_sec);
408  snowMsg->setTimeUsec(packet->time_usec);
409  sendMessageToLowerTier(snowMsg);
410  }
411 }
412 
414 {
415  unsigned int i;
416 
417  if(doRealworld) {
418  int packetSize;
419 
420  SCRemovePacket removePacket;
421  removePacket.packetType = SC_REMOVE_NEIGHBOR;
422  packetSize = sizeof(removePacket);
423 
424  for(i=0; i<sgcMsg->getRemoveNeighborArraySize(); ++i) {
425  removePacket.ip = sgcMsg->getRemoveNeighbor(i).getIp().get4().getInt();
426  scheduler->sendBytes((const char*)&packetSize, sizeof(int), 0, 0, true, appFd);
427  scheduler->sendBytes((const char*)&removePacket, packetSize, 0, 0, true, appFd);
428  }
429 
430  SCAddPacket addPacket;
431  addPacket.packetType = SC_ADD_NEIGHBOR;
432  packetSize = sizeof(addPacket);
433 
434  for(i=0; i<sgcMsg->getAddNeighborArraySize(); ++i) {
435  addPacket.ip = sgcMsg->getAddNeighbor(i).getIp().get4().getInt();
436  if( addPacket.ip == thisNode.getIp().get4().getInt() ) continue;
437  addPacket.posX = sgcMsg->getNeighborPosition(i).x;
438  addPacket.posY = sgcMsg->getNeighborPosition(i).y;
439  scheduler->sendBytes((const char*)&packetSize, sizeof(int), 0, 0, true, appFd);
440  scheduler->sendBytes((const char*)&addPacket, packetSize, 0, 0, true, appFd);
441  }
442  }
443  for(i=0; i<sgcMsg->getRemoveNeighborArraySize(); ++i)
444  Neighbors.erase(sgcMsg->getRemoveNeighbor(i));
445 
446  for(i=0; i<sgcMsg->getAddNeighborArraySize(); ++i) {
447  Vector2D newPos;
448  newPos = sgcMsg->getNeighborPosition(i);
449  itNeighbors = Neighbors.find(sgcMsg->getAddNeighbor(i));
450  if(itNeighbors != Neighbors.end()) {
451  Vector2D temp = newPos - itNeighbors->second.position;
452  temp.normalize();
453  itNeighbors->second.direction = temp;
454  itNeighbors->second.position = newPos;
455  }
456  else {
457  NeighborMapEntry entry;
458  entry.position = newPos;
459  Neighbors.insert(std::make_pair(sgcMsg->getAddNeighbor(i), entry));
460  }
461  }
462 }
463 
465 {
466  if(!frozen) {
467  Generator->move();
468  }
470  GameAPIPositionMessage *posMsg = new GameAPIPositionMessage("MOVEMENT_INDICATION");
472  posMsg->setPosition(position);
473  sendMessageToLowerTier(posMsg);
474 }
475 
477 {
479  globalStatistics->addStdDev("SimpleGameClient: average non-hotspot AOI",
481  }
483  globalStatistics->addStdDev("SimpleGameClient: average far-from-hotspot AOI",
485  }
487  globalStatistics->addStdDev("SimpleGameClient: average hotspot AOI",
489  }
490 }
491 
493 {
494  // destroy self timer messages
495  cancelAndDelete(move_timer);
496  cancelAndDelete(packetNotification);
497  delete Generator;
498 }