Client.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403
  1. #include "Client.h"
  2. #include "../lib/Connection.h"
  3. #include "../StartInfo.h"
  4. #include "../map.h"
  5. #include "../CGameState.h"
  6. #include "../CGameInfo.h"
  7. #include "../mapHandler.h"
  8. #include "../CCallback.h"
  9. #include "../CPlayerInterface.h"
  10. #include "../CConsoleHandler.h"
  11. #include "../lib/NetPacks.h"
  12. #include <boost/bind.hpp>
  13. #include <boost/thread.hpp>
  14. #include <boost/foreach.hpp>
  15. #include "../hch/CObjectHandler.h"
  16. #include "../hch/CGeneralTextHandler.h"
  17. #include "../hch/CArtHandler.h"
  18. #include <boost/thread/shared_mutex.hpp>
  19. #include "../lib/VCMI_Lib.h"
  20. CSharedCond<std::set<IPack*> > mess(new std::set<IPack*>);
  21. std::string toString(MetaString &ms)
  22. {
  23. std::string ret;
  24. for(int i=0;i<ms.message.size();i++)
  25. {
  26. if(ms.message[i]>0)
  27. {
  28. ret += ms.strings[ms.message[i]-1];
  29. }
  30. else
  31. {
  32. std::vector<std::string> *vec;
  33. int type = ms.texts[-ms.message[i]-1].first,
  34. ser = ms.texts[-ms.message[i]-1].second;
  35. if(type == 5)
  36. {
  37. ret += CGI->arth->artifacts[ser].name;
  38. continue;
  39. }
  40. else if(type == 7)
  41. {
  42. ret += CGI->creh->creatures[ser].namePl;
  43. continue;
  44. }
  45. else if(type == 9)
  46. {
  47. ret += CGI->objh->mines[ser].first;
  48. continue;
  49. }
  50. else if(type == 10)
  51. {
  52. ret += CGI->objh->mines[ser].second;
  53. continue;
  54. }
  55. else
  56. {
  57. switch(type)
  58. {
  59. case 1:
  60. vec = &CGI->generaltexth->allTexts;
  61. break;
  62. case 2:
  63. vec = &CGI->objh->xtrainfo;
  64. break;
  65. case 3:
  66. vec = &CGI->objh->names;
  67. break;
  68. case 4:
  69. vec = &CGI->objh->restypes;
  70. break;
  71. case 6:
  72. vec = &CGI->generaltexth->arraytxt;
  73. break;
  74. case 8:
  75. vec = &CGI->objh->creGens;
  76. break;
  77. case 11:
  78. vec = &CGI->objh->advobtxt;
  79. }
  80. ret += (*vec)[ser];
  81. }
  82. }
  83. }
  84. for(int i=0;i<ms.replacements.size();i++)
  85. {
  86. ret.replace(ret.find("%s"),2,ms.replacements[i]);
  87. }
  88. return ret;
  89. }
  90. CClient::CClient(void)
  91. {
  92. }
  93. CClient::CClient(CConnection *con, StartInfo *si)
  94. :serv(con)
  95. {
  96. timeHandler tmh;
  97. CGI->state = new CGameState();
  98. THC std::cout<<"\tGamestate: "<<tmh.getDif()<<std::endl;
  99. CConnection &c(*con);
  100. ////////////////////////////////////////////////////
  101. ui8 pom8;
  102. c << ui8(2) << ui8(1); //new game; one client
  103. c << *si;
  104. c >> pom8;
  105. if(pom8) throw "Server cannot open the map!";
  106. c << ui8(si->playerInfos.size());
  107. for(int i=0;i<si->playerInfos.size();i++)
  108. c << ui8(si->playerInfos[i].color);
  109. ui32 seed, sum;
  110. std::string mapname;
  111. c >> mapname >> sum >> seed;
  112. THC std::cout<<"\tSending/Getting info to/from the server: "<<tmh.getDif()<<std::endl;
  113. Mapa * mapa = new Mapa(mapname);
  114. THC std::cout<<"Reading and detecting map file (together): "<<tmh.getDif()<<std::endl;
  115. std::cout << "\tServer checksum for "<<mapname <<": "<<sum << std::endl;
  116. std::cout << "\tOur checksum for the map: "<< mapa->checksum << std::endl;
  117. if(mapa->checksum != sum)
  118. {
  119. #ifndef __GNUC__
  120. throw std::exception("Wrong checksum");
  121. #else
  122. throw std::exception();
  123. #endif
  124. exit(-1);
  125. }
  126. std::cout << "\tUsing random seed: "<<seed << std::endl;
  127. gs = CGI->state;
  128. gs->scenarioOps = si;
  129. gs->init(si,mapa,seed);
  130. CGI->mh = new CMapHandler();
  131. THC std::cout<<"Initializing GameState (together): "<<tmh.getDif()<<std::endl;
  132. CGI->mh->map = mapa;
  133. THC std::cout<<"Creating mapHandler: "<<tmh.getDif()<<std::endl;
  134. CGI->mh->init();
  135. THC std::cout<<"Initializing mapHandler (together): "<<tmh.getDif()<<std::endl;
  136. for (int i=0; i<CGI->state->scenarioOps->playerInfos.size();i++) //initializing interfaces
  137. {
  138. ui8 color = gs->scenarioOps->playerInfos[i].color;
  139. CCallback *cb = new CCallback(gs,color,this);
  140. if(!gs->scenarioOps->playerInfos[i].human)
  141. playerint[color] = static_cast<CGameInterface*>(CAIHandler::getNewAI(cb,"EmptyAI.dll"));
  142. else
  143. {
  144. gs->currentPlayer = color;
  145. playerint[color] = new CPlayerInterface(color,i);
  146. playerint[color]->init(cb);
  147. }
  148. }
  149. CGI->consoleh->cb = new CCallback(gs,-1,this);
  150. }
  151. CClient::~CClient(void)
  152. {
  153. }
  154. void CClient::process(int what)
  155. {
  156. switch (what)
  157. {
  158. case 100: //one of our interaces has turn
  159. {
  160. ui8 player;
  161. *serv >> player;//who?
  162. std::cout << "It's turn of "<<(unsigned)player<<" player."<<std::endl;
  163. boost::thread(boost::bind(&CGameInterface::yourTurn,playerint[player]));
  164. break;
  165. }
  166. case 101:
  167. {
  168. NewTurn n;
  169. *serv >> n;
  170. std::cout << "New day: "<<(unsigned)n.day<<". Applying changes... ";
  171. gs->apply(&n);
  172. std::cout << "done!"<<std::endl;
  173. break;
  174. }
  175. case 102: //set resource amount
  176. {
  177. SetResource sr;
  178. *serv >> sr;
  179. std::cout << "Set amount of "<<CGI->objh->restypes[sr.resid]
  180. << " of player "<<(unsigned)sr.player <<" to "<<sr.val<<std::endl;
  181. gs->apply(&sr);
  182. playerint[sr.player]->receivedResource(sr.resid,sr.val);
  183. break;
  184. }
  185. case 103: //show info dialog
  186. {
  187. InfoWindow iw;
  188. *serv >> iw;
  189. std::vector<Component*> comps;
  190. for(int i=0;i<iw.components.size();i++)
  191. comps.push_back(&iw.components[i]);
  192. playerint[iw.player]->showInfoDialog(toString(iw.text),comps);
  193. break;
  194. }
  195. case 104:
  196. {
  197. SetResources sr;
  198. *serv >> sr;
  199. std::cout << "Set amount of resources of player "<<(unsigned)sr.player<<std::endl;
  200. gs->apply(&sr);
  201. playerint[sr.player]->receivedResource(-1,-1);
  202. break;
  203. }
  204. case 105:
  205. {
  206. SetPrimSkill sps;
  207. *serv >> sps;
  208. std::cout << "Changing hero primary skill"<<std::endl;
  209. gs->apply(&sps);
  210. playerint[gs->getHero(sps.id)->tempOwner]->heroPrimarySkillChanged(gs->getHero(sps.id),sps.which,sps.val);
  211. break;
  212. }
  213. case 107:
  214. {
  215. ShowInInfobox sii;
  216. *serv >> sii;
  217. SComponent sc(sii.c);
  218. sc.description = toString(sii.text);
  219. if(playerint[sii.player]->human)
  220. static_cast<CPlayerInterface*>(playerint[sii.player])->showComp(sc);
  221. break;
  222. }
  223. case 500:
  224. {
  225. RemoveHero rh;
  226. *serv >> rh;
  227. CGHeroInstance *h = static_cast<CGHeroInstance*>(gs->map->objects[rh.id]);
  228. std::cout << "Removing hero with id = "<<(unsigned)rh.id<<std::endl;
  229. CGI->mh->removeObject(h);
  230. gs->apply(&rh);
  231. playerint[h->tempOwner]->heroKilled(h);
  232. break;
  233. }
  234. case 501: //hero movement response - we have to notify interfaces and callback
  235. {
  236. TryMoveHero *th = new TryMoveHero; //will be deleted by callback after processing
  237. *serv >> *th;
  238. std::cout << "HeroMove: id="<<th->id<<"\tResult: "<<(unsigned)th->result<<"\tPosition "<<th->end<<std::endl;
  239. gs->apply(th);
  240. int player = gs->map->objects[th->id]->getOwner();
  241. if(playerint[player])
  242. {
  243. for(std::set<int3>::iterator i=th->fowRevealed.begin(); i != th->fowRevealed.end(); i++)
  244. playerint[player]->tileRevealed(*i);
  245. //boost::function<void(int3)> tr = boost::bind(&CGameInterface::tileRevealed,playerint[player]);
  246. //std::for_each(th->fowRevealed.begin(),th->fowRevealed.end(),tr);
  247. }
  248. //notify interfacesabout move
  249. int nn=0; //number of interfece of currently browsed player
  250. for(std::map<ui8, CGameInterface*>::iterator i=playerint.begin();i!=playerint.end();i++)
  251. {
  252. if(gs->players[i->first].fogOfWarMap[th->start.x-1][th->start.y][th->start.z] || gs->players[i->first].fogOfWarMap[th->end.x-1][th->end.y][th->end.z])
  253. {
  254. HeroMoveDetails hmd(th->start,th->end,static_cast<CGHeroInstance*>(gs->map->objects[th->id]));
  255. hmd.successful = th->result;
  256. i->second->heroMoved(hmd);
  257. }
  258. }
  259. //add info for callback
  260. mess.mx->lock();
  261. mess.res->insert(th);
  262. mess.mx->unlock();
  263. mess.cv->notify_all();
  264. break;
  265. }
  266. case 502:
  267. {
  268. SetGarrisons sg;
  269. *serv >> sg;
  270. gs->apply(&sg);
  271. for(std::map<ui32,CCreatureSet>::iterator i = sg.garrs.begin(); i!=sg.garrs.end(); i++)
  272. playerint[gs->map->objects[i->first]->tempOwner]->garrisonChanged(gs->map->objects[i->first]);
  273. break;
  274. }
  275. case 503:
  276. {
  277. SetStrInfo ssi;
  278. *serv >> ssi;
  279. gs->apply(&ssi);
  280. //TODO: notify interfaces
  281. break;
  282. }
  283. case 504:
  284. {
  285. NewStructures ns;
  286. *serv >> ns;
  287. gs->apply(&ns);
  288. BOOST_FOREACH(si32 bid, ns.bid)
  289. playerint[gs->map->objects[ns.tid]->tempOwner]->buildChanged(static_cast<CGTownInstance*>(gs->map->objects[ns.tid]),bid,1);
  290. break;
  291. }
  292. case 1001:
  293. {
  294. SetObjectProperty sop;
  295. *serv >> sop;
  296. std::cout << "Setting " << (unsigned)sop.what << " property of " << sop.id <<" object to "<<sop.val<<std::endl;
  297. gs->apply(&sop);
  298. break;
  299. }
  300. case 1002:
  301. {
  302. SetHoverName shn;
  303. *serv >> shn;
  304. std::cout << "Setting a name of " << shn.id <<" object to "<< toString(shn.name) <<std::endl;
  305. gs->mx->lock();
  306. gs->map->objects[shn.id]->hoverName = toString(shn.name);
  307. gs->mx->unlock();
  308. break;
  309. }
  310. case 3000:
  311. {
  312. BattleStart bs;
  313. *serv >> bs; //uses new to allocate memory for battleInfo - must be deleted when battle is over
  314. std::cout << "Starting battle!" <<std::endl;
  315. gs->apply(&bs);
  316. if(playerint.find(gs->curB->side1) != playerint.end())
  317. playerint[gs->curB->side1]->battleStart(&gs->curB->army1, &gs->curB->army2, gs->curB->tile, gs->getHero(gs->curB->hero1), gs->getHero(gs->curB->hero2), 0);
  318. if(playerint.find(gs->curB->side2) != playerint.end())
  319. playerint[gs->curB->side2]->battleStart(&gs->curB->army1, &gs->curB->army2, gs->curB->tile, gs->getHero(gs->curB->hero1), gs->getHero(gs->curB->hero2), 1);
  320. break;
  321. }
  322. case 3001:
  323. {
  324. BattleNextRound bnr;
  325. *serv >> bnr;
  326. std::cout << "Round nr " << bnr.round <<std::endl;
  327. gs->apply(&bnr);
  328. //tell players about next round
  329. if(playerint.find(gs->curB->side1) != playerint.end())
  330. playerint[gs->curB->side1]->battleNewRound(bnr.round);
  331. if(playerint.find(gs->curB->side2) != playerint.end())
  332. playerint[gs->curB->side2]->battleNewRound(bnr.round);
  333. break;
  334. }
  335. case 3002:
  336. {
  337. BattleSetActiveStack sas;
  338. *serv >> sas;
  339. std::cout << "Active stack: " << sas.stack <<std::endl;
  340. gs->apply(&sas);
  341. boost::thread(boost::bind(&CClient::waitForMoveAndSend,this,gs->curB->stacks[sas.stack]->owner));
  342. break;
  343. }
  344. case 3003:
  345. {
  346. BattleResult br;
  347. *serv >> br;
  348. std::cout << "Battle ends. Winner: " << (unsigned)br.winner<< ". Type of end: "<< (unsigned)br.result <<std::endl;
  349. if(playerint.find(gs->curB->side1) != playerint.end())
  350. playerint[gs->curB->side1]->battleEnd(&br);
  351. if(playerint.find(gs->curB->side2) != playerint.end())
  352. playerint[gs->curB->side2]->battleEnd(&br);
  353. gs->apply(&br);
  354. break;
  355. }
  356. case 9999:
  357. break;
  358. default:
  359. #ifndef __GNUC__
  360. throw std::exception("Not supported server message!");
  361. #else
  362. throw std::exception();
  363. #endif
  364. break;
  365. }
  366. }
  367. void CClient::waitForMoveAndSend(int color)
  368. {
  369. BattleAction ba = playerint[color]->activeStack(gs->curB->activeStack);
  370. *serv << ui16(3002) << ba;
  371. }
  372. void CClient::run()
  373. {
  374. try
  375. {
  376. ui16 typ;
  377. while(1)
  378. {
  379. *serv >> typ;
  380. process(typ);
  381. }
  382. } HANDLE_EXCEPTION
  383. }