00001
00002
00003
00004
00005
00006
00007 #include <boost/thread.hpp>
00008 #include <boost/asio.hpp>
00009
00010 #include <netThread.h>
00011
00012 #include <engine.h>
00013 #include <listener.h>
00014 #include <sender.h>
00015 #include <enums.h>
00016 #include <messages.h>
00017 #include <utils.h>
00018 #include <GraphicsInteractionManager.h>
00019
00020 using boost::asio::ip::udp;
00021
00022
00023 void FastEcslent::NetThread::init() {
00024 std::cout << "Initializing Net before starting thread. Engine instance Id: " << engine->instanceId << std::endl;
00025 netCommon = new NetCommon();
00026 std::pair<udp::endpoint, std::string> ippair = netCommon->getMyIP();
00027 udp::endpoint myIP = ippair.first;
00028 myIPAddress = ippair.second;
00029
00030 listener = new Listener(myIP, engine->options.networkPort, engine->options.isServer);
00031 listener->init(myIPAddress);
00032 sender = new Sender(myIP, engine->options.networkPort, engine->options.isServer);
00033 sender->init();
00034 quit = false;
00035 startTime = getCurrentTime();
00036 TICK_SLEEP_TIME = 10;
00037 sleepTime = new boost::posix_time::milliseconds(20);
00038 insideLobby = false;
00039 }
00040
00041
00042 void FastEcslent::NetThread::run() {
00043 netThread = boost::thread(&FastEcslent::NetThread::runThread, this);
00044 std::cout << "Running thread: " << netThread.get_id() << " Engine instance Id: " << engine->instanceId << std::endl;
00045 }
00046
00047 void FastEcslent::NetThread::runThread(){
00048 listener->run();
00049 sender->run();
00050
00051 while (!quit){
00052 gameTick();
00053 }
00054 }
00055
00056 void FastEcslent::NetThread::gameTick(){
00057 if(engine->gameState == LOBBY){
00058 return;
00059 }
00060
00061 if (engine->options.isServer) {
00062 serverTick();
00063 } else {
00064 clientTick();
00065 }
00066 }
00067
00068 namespace FastEcslent {
00069
00070 State* fillStateFromEnt(FastEcslent::Entity *ent){
00071 State *s = new State();
00072
00073 s->id = ent->entityId.id;
00074
00075 s->hp = ent->hitpoints;
00076 s->timeLeftToBirth = ent->timeLeftToBirth;
00077
00078 s->px = ent->pos.x;
00079 s->py = ent->pos.y;
00080 s->pz = ent->pos.z;
00081
00082 s->vx = ent->vel.x;
00083 s->vy = ent->vel.y;
00084 s->vz = ent->vel.z;
00085
00086 s->dh = ent->desiredHeading;
00087 s->ds = ent->desiredSpeed;
00088
00089 s->rSpeed = 0.0;
00090 s->yaw = ent->yaw;
00091
00092 s->flag = 0;
00093
00094 return s;
00095 }
00096
00097 Info *fillInfoFromEnt(FastEcslent::Entity *ent){
00098 Info *info = new Info();
00099 char tmp[256];
00100 sprintf(tmp, "%255i", ent->entityType);
00101 strcpy(info->type, tmp);
00102 sprintf(tmp, "%255s", ent->uiname.c_str());
00103 strcpy(info->label, tmp);
00104
00105
00106 info->beam = ent->width;
00107 info->draft = ent->depth;
00108 info->id = ent->entityId.id;
00109 info->length = ent->length;
00110 info->playerId = ent->entityId.player;
00111 info->side = ent->entityId.side;
00112 info->maxSpeed = ent->maxSpeed;
00113 info->maxSpeedReverse = 0.0f;
00114 return info;
00115 }
00116
00117 Message *makeMessageWithStateHeader(int nEnts, long dtime){
00118 Message *m = new Message();
00119 m->head.msgType = STATEMESSAGETYPE;
00120 m->head.millisecondsFromStart = dtime;
00121 m->head.numberOfStructs = nEnts;
00122 m->head.sizeOfStruct = StateSize;
00123 return m;
00124 }
00125
00126 Message *makeMessageWithInfoHeader(int nEnts, long dtime){
00127 Message *m = new Message();
00128 m->head.msgType = INFOMESSAGETYPE;
00129 m->head.millisecondsFromStart = dtime;
00130 m->head.numberOfStructs = nEnts;
00131 m->head.sizeOfStruct = InfoSize;
00132 return m;
00133 }
00134
00135 }
00136
00137 void FastEcslent::NetThread::sendCommands(){
00138 sendUnknownEntQueries();
00139 combineCommandsIntoNetMessage();
00140 combineSquelchesIntoNetMessage();
00141
00142 }
00143
00144 void FastEcslent::NetThread::combineCommandsIntoNetMessage(){
00145 if (commandQueue.size() > 0){
00146 Message *m = new Message();
00147
00148 m->head.msgType = COMMANDENTITYMESSAGETYPE;
00149 m->head.millisecondsFromStart = netCommon->getCurrentTimeLong();
00150 m->head.numberOfStructs = commandQueue.size() ;
00151 m->head.sizeOfStruct = CommandEntitySize;
00152 unsigned int offset = 0;
00153 for(int i=0; i< m->head.numberOfStructs; i++){
00154 CommandEntity* cmd = commandQueue.front();
00155 commandQueue.pop_front();
00156 memcpy((void*)(m->data + offset), (void *)cmd, CommandEntitySize);
00157 offset += CommandEntitySize;
00158 delete cmd;
00159 }
00160
00161 sender->addMessage(m);
00162 }
00163 }
00164
00165 void FastEcslent::NetThread::combineSquelchesIntoNetMessage(){
00166 if (squelchQueue.size() > 0){
00167 Message *m = new Message();
00168
00169 m->head.msgType = SQUELCHMESSAGETYPE;
00170 m->head.millisecondsFromStart = netCommon->getCurrentTimeLong();
00171 m->head.numberOfStructs = squelchQueue.size() ;
00172 m->head.sizeOfStruct = SquelchEntitySize;
00173 unsigned int offset = 0;
00174 for(int i=0; i< m->head.numberOfStructs; i++){
00175 SquelchEntity* squelch = squelchQueue.front();
00176 squelchQueue.pop_front();
00177 memcpy((void*)(m->data + offset), (void *)squelch, SquelchEntitySize);
00178 offset += SquelchEntitySize;
00179 delete squelch;
00180 }
00181
00182 sender->addMessage(m);
00183 }
00184 }
00185
00186
00187 void FastEcslent::NetThread::addCommand(CommandEntity* m){
00188 commandQueue.push_back(m);
00189 }
00190
00191 void FastEcslent::NetThread::addSquelch(SquelchEntity* s){
00192 squelchQueue.push_back(s);
00193 }
00194
00195
00196 void FastEcslent::NetThread::sendUnknownEntQueries(){
00197 if(unknows.size()> 0) {
00198 std::cout<<"Unknowns entity count: "<< unknows.size() <<std::endl;
00199
00200 unsigned int offset = 0;
00201
00202 Message *m = new Message();
00203 m->head.msgType = REQUESTINFOMESSAGETYPE;
00204 m->head.millisecondsFromStart = netCommon->getCurrentTimeLong();
00205 m->head.numberOfStructs = unknows.size();
00206 m->head.sizeOfStruct = ReqInfoSize;
00207
00208 for (std::map<int, State*>::iterator i= unknows.begin(); i!=unknows.end();i++) {
00209 ReqInfo* reqInfo = new ReqInfo();
00210 reqInfo->id = i->first;
00211 memcpy((void*)(m->data + offset), (void *)reqInfo, ReqInfoSize);
00212 offset += ReqInfoSize;
00213 delete reqInfo;
00214 }
00215
00216 sender->addPriorityMessage(m);
00217 }
00218 }
00219
00220 void FastEcslent::NetThread::sendCommand(int id, float dh, float ds){
00221 Message *m = new Message();
00222 m->head.msgType = COMMANDENTITYMESSAGETYPE;
00223 m->head.millisecondsFromStart = (getCurrentTime() - startTime).total_milliseconds();
00224 m->head.numberOfStructs = 1;
00225 m->head.sizeOfStruct = CommandEntitySize;
00226
00227 CommandEntity* cmd = new CommandEntity();
00228 cmd->id = id;
00229 cmd->dh = dh;
00230 cmd->ds = ds;
00231 memcpy((void*)(m->data), (void *)cmd, CommandEntitySize);
00232 delete cmd;
00233
00234 sender->addMessage(m);
00235 }
00236
00237 void FastEcslent::NetThread::serverTick(){
00238 handleClientMessages();
00239 serve();
00240 boost::this_thread::sleep(*sleepTime);
00241 }
00242
00243 void FastEcslent::NetThread::clientTick(){
00244 this->handleServerMessages();
00245 sendCommands();
00246 boost::this_thread::sleep(*sleepTime);
00247 }
00248
00249 void FastEcslent::NetThread::serve(){
00250
00251 Message *message;
00252 State *state;
00253 unsigned int offset = 0;
00254
00255 int n = engine->entityMgr->nEnts;
00256
00257
00258 long dt = netCommon->getCurrentTimeLong();
00259 message = makeMessageWithStateHeader(n, netCommon->getCurrentTimeLong());
00260 offset = 0;
00261 for (int i = 0; i < n; i++) {
00262 state = fillStateFromEnt(engine->entityMgr->ents[i]);
00263
00264 memcpy((void*)(message->data + offset), (void *)state, StateSize);
00265 offset += StateSize;
00266 delete state;
00267 }
00268
00269 sender->addMessage(message);
00270 }
00271
00272 void FastEcslent::NetThread::handleClientMessages(){
00273 Message *m = listener->dequeMessage();
00274 while (m) {
00275 if((int) m->head.msgType != FastEcslent::STATEMESSAGETYPE) {
00276 handleMessage(m);
00277 }
00278 delete m;
00279 m = listener->dequeMessage();
00280 }
00281 }
00282
00283 void FastEcslent::NetThread::handleServerMessages(){
00284 Message *m = listener->dequeMessage();
00285 while (m) {
00286 if((int) m->head.msgType == FastEcslent::STATEMESSAGETYPE) {
00287 updateState(m);
00288 }else if((int) m->head.msgType == FastEcslent::INFOMESSAGETYPE) {
00289 createEnt(m);
00290 }else if ((int) m->head.msgType == FastEcslent::SQUELCHMESSAGETYPE){
00291 squelchEnts(m);
00292 }else if ((int) m->head.msgType == FastEcslent::CREATEENTITYRESPONSEMESSAGETYPE){
00293 createEntFromClientRes(m);
00294 }else if ((int) m->head.msgType == FastEcslent::MINERALPATCHIDRESPONSETYPE){
00295 updateMineralPatchID(m);
00296 }
00297 delete m;
00298 m = listener->dequeMessage();
00299 }
00300 }
00301
00302 void FastEcslent::NetThread::updateState(Message *m){
00303 unsigned int offset = 0;
00304 for(int i=0;i<m->head.numberOfStructs;i++){
00305 State *state = new State();
00306 memcpy((void *)state, (void*)(m->data + offset), StateSize);
00307 offset += StateSize;
00308 state->flag = m->head.millisecondsFromStart;
00309 updateState(state);
00310
00311 }
00312 }
00313
00314 void FastEcslent::NetThread::updateState(State *s){
00315 if(netIdToEntMap.find(s->id) != netIdToEntMap.end()){
00316 FastEcslent::Entity *ent= netIdToEntMap[s->id];
00317 NetAspect *na = dynamic_cast<NetAspect *> (ent->getAspect(NET));
00318 if(na){
00319 ent->netAspect->updateQueue.push_back(s);
00320 }else{
00321 delete s;
00322 }
00323 }
00324 else{
00325 State *tmp = unknows[s->id];
00326 unknows[s->id] = s;
00327 if (tmp != NULL)
00328 delete tmp;
00329 }
00330 }
00331
00332 void FastEcslent::NetThread::createEntFromClientReq(int builderid, EntityType entType, Ogre::Vector3 pos){
00333 CreateEntityRequest* ent = new CreateEntityRequest();
00334 ent->builderid = builderid;
00335 ent->entType = entType;
00336 ent->yaw = 0.0;
00337 ent->side = this->engine->options.side;
00338 ent->player = this->engine->options.player;
00339 ent->px = pos.x;
00340 ent->py = pos.y;
00341 ent->pz = pos.z;
00342
00343 Message *m = new Message();
00344
00345 m->head.msgType = CREATEENTITYREQUESTMESSAGETYPE;
00346 m->head.millisecondsFromStart = netCommon->getCurrentTimeLong();
00347 m->head.numberOfStructs = 1 ;
00348 m->head.sizeOfStruct = CreateEntityRequestSize;
00349
00350 memcpy((void*)(m->data), (void *)ent, CreateEntityRequestSize);
00351
00352 delete ent;
00353
00354 sender->addMessage(m);
00355 }
00356
00357 void FastEcslent::NetThread::createEntFromClientReq(Message *m){
00358 CreateEntityRequest *ent = new CreateEntityRequest();
00359 memcpy((void *)ent, (void*)(m->data), CreateEntityRequestSize);
00360 Entity* newEnt = this->engine->entityMgr->createEntityForPlayerAndSide((EntityType)(ent->entType), Ogre::Vector3(ent->px,ent->py,ent->pz), ent->yaw, (Side)(ent->side), (Player)(ent->player));
00361
00362 this->createEntFromClientRes(ent->builderid, newEnt->entityId.id);
00363 }
00364
00365 void FastEcslent::NetThread::createEntFromClientRes(int builderid, int builtid){
00366 CreateEntityResponse* ent = new CreateEntityResponse();
00367 ent->builderid = builderid;
00368 ent->builtid = builtid;
00369
00370 Message *m = new Message();
00371
00372 m->head.msgType = CREATEENTITYRESPONSEMESSAGETYPE;
00373 m->head.millisecondsFromStart = netCommon->getCurrentTimeLong();
00374 m->head.numberOfStructs = 1 ;
00375 m->head.sizeOfStruct = CreateEntityResponseSize;
00376
00377 memcpy((void*)(m->data), (void *)ent, CreateEntityResponseSize);
00378
00379 delete ent;
00380
00381 sender->addMessage(m);
00382 }
00383
00384 void FastEcslent::NetThread::createEntFromClientRes(Message *m){
00385 CreateEntityResponse *ent = new CreateEntityResponse();
00386 memcpy((void *)ent, (void*)(m->data), CreateEntityResponseSize);
00387 int builderid = ent->builderid;
00388 int builtid = ent->builtid;
00389 Entity* builder = this->engine->entityMgr->getEntityById(builderid);
00390 builder->netAspect->setEntityBeingBuilt(builtid);
00391 }
00392
00393 void FastEcslent::NetThread::createEnt(Message *m){
00394 unsigned int offset = 0;
00395 for(int i=0;i<m->head.numberOfStructs;i++){
00396 Info *info = new Info();
00397 memcpy((void *)info, (void*)(m->data + offset), InfoSize);
00398 offset += InfoSize;
00399 createEnt(info);
00400 }
00401 }
00402
00403 void FastEcslent::NetThread::createEnt(Info *info){
00404 if(unknows.find(info->id) != unknows.end()){
00405 int type = atoi(info->type);
00406 EntityType et = (EntityType)type;
00407 Side side = (Side)(info->side);
00408 Player player = (Player)(info->playerId);
00409 State *s = unknows[info->id];
00410
00411 Ogre::Vector3 pos(s->px,s->py,s->pz);
00412
00413 Entity* ent = engine->entityMgr->createEntityForPlayerAndSide(et, pos, s->yaw, side, player );
00414
00415 engine->gameMgr->pop[player] += engine->gameMgr->entTypeData[ent->entityType].supply;
00416 engine->gameMgr->currentEntityCounts[player][ent->entityType]++;
00417 engine->gameMgr->playerEnts[player][engine->gameMgr->playerNEnts[player]++] = ent;
00418
00419 ent->width = info->beam;
00420 ent->depth = info->draft;
00421 ent->uiname = info->label;
00422 ent->length = info->length;
00423 ent->maxSpeed = info->maxSpeed;
00424
00425 ent->vel.x = s->vx;
00426 ent->vel.y = s->vy;
00427 ent->vel.z = s->vz;
00428
00429 ent->timeLeftToBirth = s->timeLeftToBirth;
00430 ent->hitpoints = s->hp;
00431
00432 netIdToEntMap[info->id] = ent;
00433 netEntToIdMap[ent] = info->id;
00434
00435 ent->desiredHeading = s->dh;
00436 ent->desiredSpeed = s->ds;
00437
00438 ent->ai->state = NETSLAVE;
00439
00440
00441 delete s;
00442 unknows.erase(info->id);
00443 delete info;
00444
00445
00446 }
00447 }
00448
00449 void FastEcslent::NetThread::squelchEnts(Message *m){
00450 unsigned int offset = 0;
00451 for(int i=0;i<m->head.numberOfStructs;i++){
00452 SquelchEntity *squelch = new SquelchEntity();
00453 memcpy((void *)squelch, (void*)(m->data + offset), SquelchEntitySize);
00454 offset += SquelchEntitySize;
00455 netIdToEntMap[squelch->id]->netAspect->squalch();
00456 delete squelch;
00457 }
00458 }
00459
00460 void FastEcslent::NetThread::handleMessage(Message *m){
00461 switch((int) m->head.msgType) {
00462 case FastEcslent::REQUESTINFOMESSAGETYPE:
00463 sendInfo(m);
00464 break;
00465 case FastEcslent::COMMANDENTITYMESSAGETYPE:
00466 propagateCommand(m);
00467 break;
00468 case FastEcslent::SQUELCHMESSAGETYPE:
00469
00470 break;
00471 case FastEcslent::CREATEENTITYREQUESTMESSAGETYPE:
00472 createEntFromClientReq(m);
00473 break;
00474 case FastEcslent::MINERALPATCHIDREQUESTTYPE:
00475 responseMineralPatchID(m);
00476 break;
00477 default:
00478 break;
00479
00480 }
00481 }
00482
00483 void FastEcslent::NetThread::sendInfo(Message *m){
00484 Entity *ent;
00485 Info *info;
00486 ptime currentTime = getCurrentTime();
00487 time_duration diff = currentTime - startTime;
00488 Message *sendInfoMessage = makeMessageWithInfoHeader(m->head.numberOfStructs, diff.total_milliseconds());
00489
00490 int offset = HeaderSize;
00491
00492 FastEcslent::printMessageHeader(m->head);
00493 FastEcslent::printMessageData(m);
00494 for(int i = 0; i < m->head.numberOfStructs; i++){
00495 ent = engine->entityMgr->ents[*((int *)m->data + i)];
00496 info = fillInfoFromEnt(ent);
00497 std::cout << "Sending info message about ent with id: " << ent->entityId.id << std::endl;
00498 memcpy((void* ) ((char*)sendInfoMessage + offset), info, InfoSize);
00499 offset += InfoSize;
00500
00501 delete info;
00502 }
00503
00504 sender->addMessage(sendInfoMessage);
00505 }
00506
00507 void FastEcslent::NetThread::propagateCommand(Message *m){
00508 unsigned int offset = 0;
00509 for(int i=0;i<m->head.numberOfStructs;i++){
00510 CommandEntity *cmd = new CommandEntity();
00511 memcpy((void *)cmd, (void*)(m->data + offset), CommandEntitySize);
00512 offset += CommandEntitySize;
00513 Entity* ent = engine->entityMgr->getEntityById(cmd->id);
00514 ent->desiredHeading = cmd->dh;
00515 ent->desiredSpeed = cmd->ds;
00516 if(ent->entityClass == SURFACE){
00517 ent->ai->state = NETSLAVE;
00518 }
00519 delete cmd;
00520 }
00521 }
00522
00523 void FastEcslent::NetThread::stop(){
00524 quit = true;
00525 }
00526
00527
00528 void FastEcslent::NetThread::stopAndJoin(){
00529 stop();
00530 std::cout << "NetThread Stopping...Quit = " << std::endl;
00531 boost::this_thread::sleep(boost::posix_time::seconds(2));
00532 sender->stop();
00533 boost::this_thread::sleep(boost::posix_time::seconds(2));
00534 listener->stop();
00535 boost::this_thread::sleep(boost::posix_time::seconds(2));
00536
00537 std::cout << "NetThread Joining..." << std::endl;
00538
00539
00540 sender->join();
00541 boost::this_thread::sleep(boost::posix_time::seconds(2));
00542
00543
00544 listener->kill();
00545 sender->kill();
00546
00547 boost::this_thread::sleep(boost::posix_time::seconds(2));
00548
00549 netThread.join();
00550 }
00551
00552 int FastEcslent::NetThread::getNetId(Entity* ent){
00553 for(std::map<int, Entity*>::iterator i = netIdToEntMap.begin(); i!= netIdToEntMap.end(); i++){
00554 if(i->second == ent)
00555 return i->first;
00556 }
00557 return -1;
00558 }
00559
00560 FastEcslent::Entity* FastEcslent::NetThread::getEntityFromNetId(int entID){
00561 for(std::map<int, Entity*>::iterator i = netIdToEntMap.begin(); i!= netIdToEntMap.end(); i++){
00562 if(i->first == entID)
00563 return i->second;
00564 }
00565 return NULL;
00566 }
00567
00568 void FastEcslent::NetThread::requestMineralPatchID(int mineralid){
00569 MineralPatchIDRequest* req = new MineralPatchIDRequest();
00570 req->mineralid = mineralid;
00571
00572 Message *m = new Message();
00573
00574 m->head.msgType = MINERALPATCHIDREQUESTTYPE;
00575 m->head.millisecondsFromStart = netCommon->getCurrentTimeLong();
00576 m->head.numberOfStructs = 1 ;
00577 m->head.sizeOfStruct = MineralPatchIDRequestSize;
00578
00579 memcpy((void*)(m->data), (void *)req, MineralPatchIDRequestSize);
00580
00581 delete req;
00582
00583 sender->addMessage(m);
00584 }
00585
00586 void FastEcslent::NetThread::responseMineralPatchID(Message *m){
00587 MineralPatchIDRequest *req = new MineralPatchIDRequest();
00588 memcpy((void *)req, (void*)(m->data), MineralPatchIDRequestSize);
00589 Entity* ent = engine->entityMgr->getEntityById(req->mineralid);
00590 delete req;
00591 if(ent->entityType == MINERALS){
00592 Minerals* mineral = dynamic_cast<Minerals*>(ent);
00593
00594 MineralPatchIDResponse* res = new MineralPatchIDResponse();
00595 res->mineralid = mineral->entityId.id;
00596 res->patchid = mineral->mineralPatchId;
00597
00598 Message *m = new Message();
00599
00600 m->head.msgType = MINERALPATCHIDRESPONSETYPE;
00601 m->head.millisecondsFromStart = netCommon->getCurrentTimeLong();
00602 m->head.numberOfStructs = 1 ;
00603 m->head.sizeOfStruct = MineralPatchIDResponseSize;
00604
00605 memcpy((void*)(m->data), (void *)res, MineralPatchIDResponseSize);
00606
00607 delete res;
00608
00609 sender->addMessage(m);
00610 }
00611 }
00612
00613 void FastEcslent::NetThread::updateMineralPatchID(Message *m){
00614 MineralPatchIDResponse *res = new MineralPatchIDResponse();
00615 memcpy((void *)res, (void*)(m->data), MineralPatchIDResponseSize);
00616 Entity* ent = this->getEntityFromNetId(res->mineralid);
00617 if(ent->entityType == MINERALS){
00618 Minerals* mineral = dynamic_cast<Minerals*>(ent);
00619 mineral->mineralPatchId = res->patchid;
00620 }
00621
00622 delete res;
00623 }
00624