ServerSelection.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607
  1. #include "ServerSelection.h"
  2. #include <AlphaField.h>
  3. #include <AsynchronCall.h>
  4. #include <Base64.h>
  5. #include <Button.h>
  6. #include <DataValidator.h>
  7. #include <File.h>
  8. #include <FileSystem.h>
  9. #include <Font.h>
  10. #include <Image.h>
  11. #include <JSON.h>
  12. #include "FactoryClient.h"
  13. #include "Globals.h"
  14. #include "Initialization.h"
  15. #include "Load.h"
  16. #include "World.h"
  17. using namespace Framework;
  18. ServerStatus::ServerStatus(Framework::Text name,
  19. Framework::Text ip,
  20. unsigned short sslPort,
  21. unsigned short port,
  22. Framework::HashMap<Framework::Text, Framework::Text>* secrets)
  23. : DrawableBackground(),
  24. name(name),
  25. ip(ip),
  26. sslPort(sslPort),
  27. port(port),
  28. playerName(""),
  29. ping(-1),
  30. status("..."),
  31. statusId(0),
  32. requestId(0),
  33. secrets(secrets),
  34. join(initButton(0, 0, 55, 20, Button::Style::Normal, "join"))
  35. {
  36. setMouseEvent(_ret1ME);
  37. setStyle(Style::Allowed | Style::Visible | Style::Border);
  38. setBorderWidth(1);
  39. setBorderColor(0xFF3d3d3d);
  40. join->setMouseEvent([this](void* p, void* o, MouseEvent me) {
  41. if (me.id == ME_RLeft)
  42. {
  43. FactoryClient* client = new FactoryClient();
  44. if (!client->connect(getIp(), getSSLPort()))
  45. {
  46. writeLock().lock();
  47. status = "The Server is currently not reachable";
  48. statusId = 404;
  49. ping = -1;
  50. rend = 1;
  51. writeLock().unlock();
  52. client->release();
  53. }
  54. else
  55. {
  56. Text secret = "";
  57. if (this->secrets->has(playerName))
  58. secret = this->secrets->get(playerName);
  59. if (statusId == 203) secret = "";
  60. bool isNew = secret.getLength() == 0;
  61. menuRegister->get("serverSelection")->hide();
  62. menuRegister->get("load")->show();
  63. ((LoadMenu*)(Menu*)menuRegister->get("load"))
  64. ->load(client,
  65. playerName,
  66. secret,
  67. getPort(),
  68. [this, isNew, client](int result, Text secret) {
  69. menuRegister->get("load")->hide();
  70. writeLock().lock();
  71. statusId = result;
  72. if (statusId == 403)
  73. status = "The name is already in use";
  74. if (statusId == 500)
  75. status = "Unknown Server message received";
  76. if (statusId == 201) status = "Please try again";
  77. writeLock().unlock();
  78. if (statusId == 200 || statusId == 201)
  79. {
  80. if (isNew)
  81. {
  82. this->secrets->put(playerName, secret);
  83. ((ServerSelectionMenu*)(Menu*)menuRegister
  84. ->get("serverSelection"))
  85. ->saveServers();
  86. }
  87. if (statusId == 200)
  88. {
  89. World::INSTANCE
  90. = new World(dynamic_cast<Screen3D*>(
  91. window->zScreen()),
  92. client);
  93. menuRegister->get("game")->show();
  94. }
  95. else
  96. {
  97. menuRegister->get("serverSelection")
  98. ->show();
  99. client->release();
  100. }
  101. }
  102. else
  103. {
  104. menuRegister->get("serverSelection")->show();
  105. client->release();
  106. }
  107. });
  108. }
  109. }
  110. return 1;
  111. });
  112. LTDBFile iconsDat;
  113. iconsDat.setFile(new Text("data/images/gui_icons.ltdb"));
  114. iconsDat.readData(0);
  115. removeButton = initButton(0,
  116. 0,
  117. 20,
  118. 20,
  119. Framework::Button::Style::BImage | Framework::Button::Style::BAlpha
  120. | Framework::Button::Style::Background,
  121. "");
  122. removeButton->setBorderColor(0xFF9C0A0A);
  123. removeButton->setAlphaFieldColor(0x5F9C0A0A);
  124. removeButton->setToolTipText("Remove player from list of ignored players",
  125. uiFactory.initParam.bildschirm,
  126. uiFactory.initParam.font);
  127. removeButton->setBackgroundImageZ(
  128. dynamic_cast<Image*>(iconsDat.load(0, new Text("trash.png"))));
  129. removeButton->setMouseEvent([this](void* p, void* o, MouseEvent me) {
  130. if (me.id == ME_RLeft)
  131. {
  132. ((ServerSelectionMenu*)(Menu*)menuRegister->get("serverSelection"))
  133. ->removeServer(this->name);
  134. }
  135. return 1;
  136. });
  137. }
  138. ServerStatus::~ServerStatus()
  139. {
  140. requestIdLock.lockRead();
  141. while (currentRequestIds.getEntryCount())
  142. {
  143. requestIdLock.unlockRead();
  144. Sleep(100); // wait until running requets are completed
  145. requestIdLock.lockRead();
  146. }
  147. requestIdLock.unlockRead();
  148. secrets->release();
  149. removeButton->release();
  150. join->release();
  151. }
  152. void ServerStatus::updatePlayerName(Framework::Text playerName)
  153. {
  154. status = "";
  155. this->playerName = playerName;
  156. requestIdLock.lockWrite();
  157. int id = ++requestId;
  158. requestIdLock.unlockWrite();
  159. bool* ready = new bool;
  160. *ready = 0;
  161. AsynchronCall* request = new AsynchronCall([this, id, ready]() {
  162. FactoryClient* client = new FactoryClient();
  163. if (!client->connect(getIp(), getSSLPort()))
  164. {
  165. requestIdLock.lockRead();
  166. if (requestId == id)
  167. {
  168. status = "The Server is currently not reachable";
  169. statusId = 404;
  170. ping = -1;
  171. rend = 1;
  172. }
  173. requestIdLock.unlockRead();
  174. }
  175. else
  176. {
  177. requestIdLock.lockRead();
  178. if (requestId == id)
  179. {
  180. Text secret = "";
  181. if (secrets->has(this->playerName))
  182. secret = secrets->get(this->playerName);
  183. requestIdLock.unlockRead();
  184. int ping = client->ping();
  185. int statusId = client->status(this->playerName, secret);
  186. if (statusId == 403)
  187. {
  188. int secondStatus = client->status(this->playerName, "");
  189. if (secondStatus == 200) statusId = 203;
  190. }
  191. if (secret.isEqual("") && statusId == 200)
  192. {
  193. statusId = 203;
  194. }
  195. requestIdLock.lockRead();
  196. if (requestId == id)
  197. {
  198. writeLock().lock();
  199. this->ping = ping;
  200. this->statusId = statusId;
  201. if (statusId == 200) status = "The Server is reachable";
  202. if (statusId == 203) status = "Create a new player";
  203. if (statusId == 403) status = "The name is already in use";
  204. rend = 1;
  205. writeLock().unlock();
  206. }
  207. }
  208. requestIdLock.unlockRead();
  209. }
  210. client->release();
  211. while (!*ready)
  212. {
  213. Sleep(100);
  214. }
  215. delete ready;
  216. requestIdLock.lockWrite();
  217. auto idIterator = currentRequestIds.begin();
  218. auto requestIterator = currentRequests.begin();
  219. while (idIterator && requestIterator)
  220. {
  221. if (*idIterator == id)
  222. {
  223. requestIterator.remove();
  224. idIterator.remove();
  225. break;
  226. }
  227. ++idIterator;
  228. ++requestIterator;
  229. }
  230. requestIdLock.unlockWrite();
  231. });
  232. requestIdLock.lockWrite();
  233. currentRequestIds.add(id);
  234. currentRequests.add(request);
  235. *ready = 1;
  236. requestIdLock.unlockWrite();
  237. }
  238. void ServerStatus::doMouseEvent(Framework::MouseEvent& me, bool userRet)
  239. {
  240. removeButton->doPublicMouseEvent(me);
  241. if (canConnect()) join->doPublicMouseEvent(me);
  242. }
  243. bool ServerStatus::tick(double time)
  244. {
  245. join->setPosition(gr.x - 60, gr.y - 25);
  246. removeButton->setPosition(gr.x - 20, 0);
  247. return DrawableBackground::tick(time) || join->tick(time)
  248. || removeButton->tick(time);
  249. }
  250. void ServerStatus::render(Framework::Image& rObj)
  251. {
  252. DrawableBackground::render(rObj);
  253. if (rObj.setDrawOptions(pos, gr))
  254. {
  255. TextRenderer tr(
  256. dynamic_cast<Font*>(uiFactory.initParam.font->getThis()));
  257. tr.setFontSize(12);
  258. tr.renderText(5, 5, name, rObj, 0xFFFFFFFF);
  259. tr.renderText(
  260. 5, 25, ip + ":" + sslPort + " (" + port + ")", rObj, 0xFF808080);
  261. if (requestId && statusId != 404)
  262. {
  263. int tbr = tr.getTextWidth(Text("ping: ") + ping);
  264. if (ping >= 0)
  265. {
  266. tr.renderText(getWidth() - 25 - tbr,
  267. 5,
  268. Text("ping: ") + ping,
  269. rObj,
  270. 0xFFFFFFFF);
  271. }
  272. }
  273. if (statusId == 404 || statusId == 500)
  274. tr.renderText(5, 45, status, rObj, 0xFFFF0000);
  275. if (statusId == 403 || statusId == 201 || statusId == 203)
  276. tr.renderText(5, 45, status, rObj, 0xFFFFA500);
  277. if (statusId == 200) tr.renderText(5, 45, status, rObj, 0xFF00FF00);
  278. removeButton->render(rObj);
  279. if (canConnect()) join->render(rObj);
  280. rObj.releaseDrawOptions();
  281. }
  282. }
  283. Framework::Text ServerStatus::getName() const
  284. {
  285. return name;
  286. }
  287. Framework::Text ServerStatus::getIp() const
  288. {
  289. return ip;
  290. }
  291. unsigned short ServerStatus::getSSLPort() const
  292. {
  293. return sslPort;
  294. }
  295. unsigned short ServerStatus::getPort() const
  296. {
  297. return port;
  298. }
  299. Framework::HashMap<Framework::Text, Framework::Text>*
  300. ServerStatus::zSecrets() const
  301. {
  302. return secrets;
  303. }
  304. bool ServerStatus::canConnect() const
  305. {
  306. return statusId == 200 || statusId == 201 || statusId == 203;
  307. }
  308. ServerSelectionMenu::ServerSelectionMenu(Screen* zScreen)
  309. : Menu(zScreen)
  310. {
  311. playerNameLabel = initTextField(zScreen->getBackBufferSize().x / 2 - 150,
  312. zScreen->getBackBufferSize().y / 2 - 300,
  313. 85,
  314. 20,
  315. TextField::Style::Text | TextField::Style::VCenter,
  316. "Player Name:");
  317. elements.add(playerNameLabel);
  318. playerName = initTextField(zScreen->getBackBufferSize().x / 2 - 150 + 85,
  319. zScreen->getBackBufferSize().y / 2 - 300,
  320. 215,
  321. 20,
  322. TextField::Style::TextField,
  323. "");
  324. playerName->setPostKeyboardEvent(
  325. [this](void* p, void* o, KeyboardEvent te) {
  326. // set player names of each server
  327. for (int i = 0; i < serverList->getEntryCount(); i++)
  328. ((ServerStatus*)serverList->zEntry(i))
  329. ->updatePlayerName(playerName->zText()->getText());
  330. saveServers();
  331. return 1;
  332. });
  333. elements.add(playerName);
  334. serverLabel = initTextField(zScreen->getBackBufferSize().x / 2 - 150,
  335. zScreen->getBackBufferSize().y / 2 - 275,
  336. 100,
  337. 20,
  338. TextField::Style::Text | TextField::Style::VCenter,
  339. "Server:");
  340. elements.add(serverLabel);
  341. refresh = initButton(zScreen->getBackBufferSize().x / 2 + 80,
  342. zScreen->getBackBufferSize().y / 2 - 275,
  343. 70,
  344. 20,
  345. Button::Style::Normal,
  346. "Refresh");
  347. refresh->setMouseEvent([this](void* p, void* o, Framework::MouseEvent me) {
  348. if (me.id == ME_RLeft)
  349. {
  350. if (playerName->zText()->getLength() > 0)
  351. {
  352. for (int i = 0; i < serverList->getEntryCount(); i++)
  353. ((ServerStatus*)serverList->zEntry(i))
  354. ->updatePlayerName(playerName->zText()->getText());
  355. }
  356. }
  357. return 1;
  358. });
  359. elements.add(refresh);
  360. serverList = new DrawableList();
  361. serverList->setSize(300, 480);
  362. serverList->setBorderWidth(1);
  363. serverList->setBorderColor(0xFF6d6d6d);
  364. serverList->setPosition(zScreen->getBackBufferSize().x / 2 - 150,
  365. zScreen->getBackBufferSize().y / 2 - 250);
  366. serverList->setStyle(
  367. DrawableList::Style::Normal | DrawableList::Style::VScroll);
  368. serverList->setMouseEvent(_ret1ME);
  369. serverList->setVerticalScrollPos(0);
  370. serverList->setEntrySeperatorSize(1);
  371. serverList->setEntrySeperatorColor(0xFF6d6d6d);
  372. elements.add(serverList);
  373. add = initButton(zScreen->getBackBufferSize().x / 2 - 50,
  374. zScreen->getBackBufferSize().y / 2 + 235,
  375. 100,
  376. 20,
  377. Button::Style::Normal,
  378. "Add Server");
  379. elements.add(add);
  380. add->setMouseEvent([this](void* p, void* o, Framework::MouseEvent me) {
  381. if (me.id == ME_RLeft)
  382. {
  383. hide();
  384. menuRegister->get("addServer")->show();
  385. }
  386. return 1;
  387. });
  388. exit = initButton(zScreen->getBackBufferSize().x / 2 - 50,
  389. zScreen->getBackBufferSize().y / 2 + 285,
  390. 100,
  391. 20,
  392. Button::Style::Normal,
  393. "Beenden");
  394. elements.add(exit);
  395. exit->setBorderColor(0xFF9C0A0A);
  396. exit->setAlphaFieldStrength(10);
  397. exit->setAlphaFieldColor(0x5F9C0A0A);
  398. exit->setMouseEvent([this](void* p, void* o, Framework::MouseEvent me) {
  399. if (me.id == ME_RLeft)
  400. {
  401. hide();
  402. StopMessageLoop(0);
  403. }
  404. return 1;
  405. });
  406. // load server json
  407. JSON::JSONValue* json = JSON::loadJSONFromFile("data/server.json");
  408. if (json)
  409. {
  410. // build validator
  411. Validator::DataValidator* validator
  412. = Validator::DataValidator::buildForObject()
  413. ->withRequiredString("playerName")
  414. ->withDefault("")
  415. ->finishString()
  416. ->withRequiredAttribute("server",
  417. Validator::DataValidator::buildForArray()
  418. ->withDefault(new JSON::JSONArray())
  419. ->removeInvalidEntries()
  420. ->addAcceptedTypeInArray(
  421. Validator::DataValidator::buildForObject()
  422. ->withRequiredString("name")
  423. ->finishString()
  424. ->withRequiredString("ip")
  425. ->finishString()
  426. ->withRequiredNumber("sslPort")
  427. ->whichIsGreaterOrEqual(0)
  428. ->whichIsLessOrEqual((double)0xFFFF)
  429. ->finishNumber()
  430. ->withRequiredNumber("port")
  431. ->whichIsGreaterOrEqual(0)
  432. ->whichIsLessOrEqual((double)0xFFFF)
  433. ->finishNumber()
  434. ->withRequiredAttribute("secrets",
  435. Validator::DataValidator::buildForArray()
  436. ->addAcceptedObjectInArray()
  437. ->withRequiredString("secret")
  438. ->finishString()
  439. ->withRequiredString("playerName")
  440. ->finishString()
  441. ->finishObject()
  442. ->finishArray())
  443. ->finishObject())
  444. ->finishArray())
  445. ->finishObject();
  446. RCArray<Validator::ValidationResult> removedParts;
  447. JSON::JSONValue* validJson
  448. = validator->getValidParts(json, &removedParts);
  449. json->release();
  450. if (validJson)
  451. {
  452. JSON::JSONArray* arr
  453. = validJson->asObject()->zValue("server")->asArray();
  454. for (int i = 0; i < arr->getLength(); i++)
  455. {
  456. JSON::JSONObject* obj = arr->zValue(i)->asObject();
  457. Framework::HashMap<Framework::Text, Framework::Text>* secrets
  458. = new Framework::HashMap<Framework::Text, Framework::Text>(
  459. 10, [](Text t) { return t.hashCode(); });
  460. JSON::JSONArray* secretsJson
  461. = obj->zValue("secrets")->asArray();
  462. for (int j = 0; j < secretsJson->getLength(); j++)
  463. {
  464. JSON::JSONObject* obj2 = secretsJson->zValue(j)->asObject();
  465. // decode base64 secret
  466. char* secretBuffer = 0;
  467. int length;
  468. Framework::base64Decode(
  469. obj2->zValue("secret")->asString()->getString(),
  470. &secretBuffer,
  471. &length);
  472. secrets->put(
  473. obj2->zValue("playerName")->asString()->getString(),
  474. Framework::Text(secretBuffer));
  475. delete[] secretBuffer;
  476. }
  477. ServerStatus* s = new ServerStatus(
  478. obj->zValue("name")->asString()->getString(),
  479. obj->zValue("ip")->asString()->getString(),
  480. (unsigned short)obj->zValue("sslPort")
  481. ->asNumber()
  482. ->getNumber(),
  483. (unsigned short)obj->zValue("port")
  484. ->asNumber()
  485. ->getNumber(),
  486. secrets);
  487. s->setSize(300, 65);
  488. serverList->addEntry(s);
  489. }
  490. playerName->setText(validJson->asObject()
  491. ->zValue("playerName")
  492. ->asString()
  493. ->getString());
  494. if (playerName->zText()->getLength() > 0)
  495. {
  496. for (int i = 0; i < serverList->getEntryCount(); i++)
  497. ((ServerStatus*)serverList->zEntry(i))
  498. ->updatePlayerName(playerName->zText()->getText());
  499. }
  500. serverList->updateVScroll();
  501. validJson->release();
  502. }
  503. validator->release();
  504. }
  505. }
  506. void ServerSelectionMenu::addServer(Framework::Text name,
  507. Framework::Text ip,
  508. unsigned short sslPort,
  509. unsigned short port)
  510. {
  511. ServerStatus* tmp = new ServerStatus(name,
  512. ip,
  513. sslPort,
  514. port,
  515. new HashMap<Framework::Text, Framework::Text>(
  516. 10, [](Text t) { return t.hashCode(); }));
  517. tmp->setSize(300, 65);
  518. serverList->addEntry(tmp);
  519. tmp->updatePlayerName(playerName->zText()->getText());
  520. serverList->updateVScroll();
  521. saveServers();
  522. }
  523. bool ServerSelectionMenu::hasServer(Framework::Text name) const
  524. {
  525. for (int i = 0; i < serverList->getEntryCount(); i++)
  526. {
  527. if (((ServerStatus*)serverList->zEntry(i))->getName() == name) return 1;
  528. }
  529. return 0;
  530. }
  531. void ServerSelectionMenu::removeServer(Framework::Text name) const
  532. {
  533. for (int i = 0; i < serverList->getEntryCount(); i++)
  534. {
  535. if (((ServerStatus*)serverList->zEntry(i))->getName() == name)
  536. serverList->removeEntry(i);
  537. }
  538. serverList->updateVScroll();
  539. saveServers();
  540. }
  541. void ServerSelectionMenu::saveServers() const
  542. {
  543. File file;
  544. file.setFile("data/server.json");
  545. file.open(File::Style::write);
  546. JSON::JSONObject root;
  547. JSON::JSONArray* servers = new JSON::JSONArray();
  548. for (int i = 0; i < serverList->getEntryCount(); i++)
  549. {
  550. JSON::JSONObject* server = new JSON::JSONObject();
  551. server->addValue("name",
  552. new JSON::JSONString(
  553. ((ServerStatus*)serverList->zEntry(i))->getName()));
  554. server->addValue("ip",
  555. new JSON::JSONString(
  556. ((ServerStatus*)serverList->zEntry(i))->getIp()));
  557. server->addValue("sslPort",
  558. new JSON::JSONNumber(
  559. ((ServerStatus*)serverList->zEntry(i))->getSSLPort()));
  560. server->addValue("port",
  561. new JSON::JSONNumber(
  562. ((ServerStatus*)serverList->zEntry(i))->getPort()));
  563. JSON::JSONArray* secrets = new JSON::JSONArray();
  564. for (auto secretEntry :
  565. *((ServerStatus*)serverList->zEntry(i))->zSecrets())
  566. {
  567. JSON::JSONObject* secret = new JSON::JSONObject();
  568. secret->addValue(
  569. "playerName", new JSON::JSONString(secretEntry.getKey()));
  570. // base64 encode secret
  571. Framework::Text secretBase64 = Framework::base64Encode(
  572. secretEntry.getValue(), secretEntry.getValue().getLength());
  573. secret->addValue("secret", new JSON::JSONString(secretBase64));
  574. secrets->addValue(secret);
  575. }
  576. server->addValue("secrets", secrets);
  577. servers->addValue(server);
  578. }
  579. root.addValue("server", servers);
  580. root.addValue(
  581. "playerName", new JSON::JSONString(playerName->zText()->getText()));
  582. Framework::Text json = root.toString();
  583. file.write(json, json.getLength());
  584. file.close();
  585. }