#include "SpielClient.h" #include #include "Keys.h" using namespace KSGClient; // Inhalt der SpielClient Klasse // Konstruktor SpielClient::SpielClient(int klientId, unsigned short port, const char* ip, const char* key, unsigned char keyLen) : ReferenceCounter() { this->ip = ip; this->port = port; cId = klientId; senden = 0; empfangen = 0; this->key = new char[keyLen]; memcpy(this->key, key, keyLen); this->keyLen = keyLen; } // Destruktor SpielClient::~SpielClient() { trenne(); delete[] key; } // verbindet sich mit dem zugewiesenen Karten Server // Gibt 1 zurück, falls der Vorgang erfolgreich ist, 0 sonnst bool SpielClient::verbinde() { cs.lock(); if (senden) { cs.unlock(); return 1; } if (!senden) senden = new Network::Klient(); int keyLen = 0; char* key = 0; Keys::getServerKey(&key, keyLen, Keys::SPIEL, Keys::SENDEN); senden->setSendeKey(key, keyLen); delete[] key; Keys::getServerKey(&key, keyLen, Keys::SPIEL, Keys::EMPFANGEN); senden->setEmpfangKey(key, keyLen); delete[] key; if (senden->verbinde(port, ip)) { if (senden->sendeEncrypted("\1", 1)) { char serverReturn = 0; senden->sendeEncrypted((char*)&cId, 4); char ret = 0; senden->getNachrichtEncrypted(&ret, 1); if (ret != 1) { if (ret == 3) { char byte = 0; senden->getNachrichtEncrypted(&byte, 1); char* f = new char[byte + 1]; f[byte] = 0; senden->getNachrichtEncrypted(f, byte); err = f; delete[]f; } senden->sendeEncrypted("\3", 1); senden->getNachrichtEncrypted(&serverReturn, 1); senden->trenne(); senden = (Network::Klient*)senden->release(); err = "Server akzeptiert den Klient nicht."; cs.unlock(); return 0; } senden->setSendeKey(this->key, this->keyLen); senden->setEmpfangKey(this->key, this->keyLen); if (!empfangen) empfangen = new Network::Klient(); int keyLen = 0; char* key = 0; Keys::getServerKey(&key, keyLen, Keys::SPIEL, Keys::SENDEN); empfangen->setSendeKey(key, keyLen); delete[] key; Keys::getServerKey(&key, keyLen, Keys::SPIEL, Keys::EMPFANGEN); empfangen->setEmpfangKey(key, keyLen); delete[] key; if (empfangen->verbinde(senden->getServerPort(), senden->getServerIp())) { empfangen->sendeEncrypted("\1", 1); empfangen->sendeEncrypted((char*)&cId, 4); char res = 0; empfangen->getNachrichtEncrypted(&res, 1); if (res == 3) { char län = 0; empfangen->getNachrichtEncrypted(&län, 1); char* nachricht = new char[län + 1]; nachricht[län] = 0; empfangen->getNachrichtEncrypted(nachricht, län); err = nachricht; delete[] nachricht; } if (res == 1) { empfangen->setSendeKey(this->key, this->keyLen); empfangen->setEmpfangKey(this->key, this->keyLen); } else if (res != 0) { err = "Fehler beim Verbinden mit dem Spiel Server."; senden->sendeEncrypted("\3", 1); char serverReturn = 0; senden->getNachrichtEncrypted(&serverReturn, 1); senden->trenne(); senden = (Network::Klient*)senden->release(); empfangen->trenne(); empfangen = (Network::Klient*)empfangen->release(); return 0; } cs.unlock(); return 1; } else { empfangen = (Network::Klient*)empfangen->release(); senden->sendeEncrypted("\3", 1); char serverReturn = 0; senden->getNachrichtEncrypted(&serverReturn, 1); senden->trenne(); senden = (Network::Klient*)senden->release(); err = "Der dir zugewiesene Spiel Server kann dir keine Nachrichten senden."; cs.unlock(); return 0; } } else { senden->trenne(); senden = (Network::Klient*)senden->release(); err = "Der dir zugewiesene Spiel Server hat die Verbindung abgebrochen. Bitte versuche es Später erneut."; cs.unlock(); return 0; } } else { err = "Der dir zugewiesene Spiel Server antwortet nicht. Bitte versuche es Später erneut."; senden = (Network::Klient*)senden->release(); cs.unlock(); return 0; } err = "Unbekannter Fehler"; cs.unlock(); return 0; } // Betritt das Vorgeschlagene Spiel // Gibt 1 zurück, falls der Vorgang erfolgreich ist, 0 sonnst bool SpielClient::spielErstelltAnnehmen() { cs.lock(); if (!senden) { err = "Der Client ist nicht verbunden."; cs.unlock(); return 0; } char ret = 0; senden->sendeEncrypted("\4", 1); senden->getNachrichtEncrypted(&ret, 1); if (ret != 1) err = "Fehler beim annehmen des Spiels."; cs.unlock(); return ret == 1; } // Lehnt das Vorgeschlagene Spiel ab // Gibt 1 zurück, falls der Vorgang erfolgreich ist, 0 sonnst bool SpielClient::spielErstelltAblehnen() { cs.lock(); if (!senden) { err = "Der Client ist nicht verbunden."; cs.unlock(); return 0; } char ret = 0; senden->sendeEncrypted("\5", 1); senden->getNachrichtEncrypted(&ret, 1); if (ret != 1) err = "Fehler beim ablehnen des Spiels."; cs.unlock(); return ret == 1; } // Wechselt zu einem bestimmten Team // team: Die Id des teams // Gibt 1 zurück, falls der Vorgang erfolgreich ist, 0 sonnst bool SpielClient::spielErstelltTeamWechseln(int team) { cs.lock(); if (!senden) { err = "Der Client ist nicht verbunden."; cs.unlock(); return 0; } char ret = 0; senden->sendeEncrypted("\6", 1); senden->getNachrichtEncrypted(&ret, 1); if (!ret) { err = "Fehler beim wechseln des Teams."; cs.unlock(); return 0; } senden->sendeEncrypted((char*)&team, 4); senden->getNachrichtEncrypted(&ret, 1); if (ret != 1) err = "Fehler beim wechseln des Teams."; cs.unlock(); return ret == 1; } // Bestätigt die Teamauswahl so dass das Spiel früher beginnen kann // Gibt 1 zurück, falls der Vorgang erfolgreich ist, 0 sonnst bool SpielClient::spielErstelltTeamFertig() { cs.lock(); if (!senden) { err = "Der Client ist nicht verbunden."; cs.unlock(); return 0; } char ret = 0; senden->sendeEncrypted("\xE", 1); senden->getNachrichtEncrypted(&ret, 1); if (ret != 1) err = "Fehler beim setzen der Bereitschaft."; cs.unlock(); return ret == 1; } // sendet eine Chat Nachricht an die mitglieder des erstellten Spiels // nachricht: Die Nachricht // Gibt 1 zurück, falls der Vorgang erfolgreich ist, 0 sonnst bool SpielClient::spielErstelltChatNachricht(const char* nachricht) { char län = textLength(nachricht); if (!län) return 1; cs.lock(); if (!senden) { err = "Der Client ist nicht verbunden."; cs.unlock(); return 0; } char ret = 0; senden->sendeEncrypted("\7", 1); senden->getNachrichtEncrypted(&ret, 1); if (!ret) { err = "Fehler beim senden der Chat Nachricht."; cs.unlock(); return 0; } senden->sendeEncrypted(&län, 1); senden->sendeEncrypted(nachricht, län); senden->getNachrichtEncrypted(&ret, 1); if (ret != 1) err = "Fehler beim senden der Chat Nachricht."; cs.unlock(); return ret == 1; } // Teilt dem Server mit, dass der Client bereit ist das Spiel zu laden // Gibt 1 zurück, falls der Vorgang erfolgreich ist, 0 sonnst bool SpielClient::bereitZumLaden() { cs.lock(); if (!senden) { err = "Der Client ist nicht verbunden."; cs.unlock(); return 0; } char ret = 0; senden->sendeEncrypted("\x9", 1); senden->getNachrichtEncrypted(&ret, 1); if (ret != 1) err = "Fehler beim setzen der Bereitschaft."; cs.unlock(); return ret == 1; } // Teilt dem Server mit, zu wie viel Prozent der Client das Spiel geladen hat // Gibt 1 zurück, falls der Vorgang erfolgreich ist, 0 sonnst bool SpielClient::setLadenProzent(int prozent) { cs.lock(); if (!senden) { err = "Der Client ist nicht verbunden."; cs.unlock(); return 0; } char ret = 0; senden->sendeEncrypted("\xC", 1); senden->getNachrichtEncrypted(&ret, 1); if (ret) { senden->sendeEncrypted((char*)&prozent, 4); senden->getNachrichtEncrypted(&ret, 1); } if (ret != 1) err = "Fehler beim setzen des Fortschritts."; cs.unlock(); return ret == 1; } // Teilt dem Server mit, dass das Spiel fertig geladen wurde // Gibt 1 zurück, falls der Vorgang erfolgreich ist, 0 sonnst bool SpielClient::bereitZumSpiel() { cs.lock(); if (!senden) { err = "Der Client ist nicht verbunden."; cs.unlock(); return 0; } char ret = 0; senden->sendeEncrypted("\xA", 1); senden->getNachrichtEncrypted(&ret, 1); if (ret != 1) err = "Fehler beim setzen der Bereitschaft."; cs.unlock(); return ret == 1; } // Sendet während des Spiels eine Nachricht an den Server // län: Die Länge der Nachricht // bytes: Ein Zeiger auf die Nachricht // Gibt 1 zurück, falls der Vorgang erfolgreich ist, 0 sonnst bool SpielClient::spielNachricht(short län, const char* bytes) { cs.lock(); if (!senden) { err = "Der Client ist nicht verbunden."; cs.unlock(); return 0; } senden->sendeEncrypted("\xB", 1); senden->sende((char*)&län, 2); senden->sende(bytes, län); cs.unlock(); return 1; } // Sendet während der Statistik eine Nachricht an den Server // län: Die Länge der Nachricht // bytes: Ein Zeiger auf die Nachricht // Gibt 1 zurück, falls der Vorgang erfolgreich ist, 0 sonnst bool SpielClient::statistikNachricht(short län, const char* bytes) { cs.lock(); if (!senden) { err = "Der Client ist nicht verbunden."; cs.unlock(); return 0; } char ret = 0; senden->sendeEncrypted("\xD", 1); senden->getNachrichtEncrypted(&ret, 1); if (ret) { senden->sendeEncrypted((char*)&län, 2); senden->sendeEncrypted(bytes, län); senden->getNachrichtEncrypted(&ret, 1); } if (ret != 1) err = "Fehler beim setzen der Statistik Nachricht."; cs.unlock(); return ret == 1; } // Wartet auf eine Nachricht vom Spiel Server. // Gibt bei Erfolg 1 zurück, 0 sonnst // nachricht: Eine Referenz auf die Struktur, in der die Nachricht gespeichert werden soll bool SpielClient::getNextMessage(SpielServerNachricht& nachricht) { do { if (!empfangen->getNachrichtEncrypted(&nachricht.type, 1)) { err = "Es ist ein Fehler beim Empfangen aufgetreten"; return 0; } switch (nachricht.type) { case 0: // verbindung getrennt trenne(); break; case 1: // verbleibende Zeit empfangen->getNachrichtEncrypted(&nachricht.sekunden, 1); break; case 2: // SpielErstellt abbruch if (1) { char län = 0; empfangen->getNachrichtEncrypted(&län, 1); char* grund = new char[län + 1]; grund[län] = 0; empfangen->getNachrichtEncrypted(grund, län); nachricht.message = grund; delete[] grund; } break; case 3: // Fehler if (1) { unsigned char länge = 0; empfangen->getNachrichtEncrypted((char*)&länge, 1); char* txt = new char[länge + 1]; txt[länge] = 0; empfangen->getNachrichtEncrypted(txt, länge); nachricht.message = txt; delete[]txt; } break; case 4: // zurück in Warteschlange empfangen->getNachrichtEncrypted(&nachricht.stunden, 1); empfangen->getNachrichtEncrypted(&nachricht.minuten, 1); empfangen->getNachrichtEncrypted(&nachricht.sekunden, 1); break; case 6: // SpielErstellt Initialisierung empfangen->getNachrichtEncrypted((char*)&nachricht.sts->spielerAnzahl, 4); empfangen->getNachrichtEncrypted((char*)&nachricht.sts->teamAnzahl, 4); for (int i = 0; i < nachricht.sts->spielerAnzahl; i++) { int farbe = 0; empfangen->getNachrichtEncrypted((char*)&farbe, 4); nachricht.sts->spielerFarbe->set(farbe, i); } for (int i = 0; i < nachricht.sts->teamAnzahl; i++) { int farbe = 0; empfangen->getNachrichtEncrypted((char*)&farbe, 4); nachricht.sts->teamFarbe->set(farbe, i); } for (int i = 0; i < nachricht.sts->teamAnzahl; i++) { char län = 0; empfangen->getNachrichtEncrypted(&län, 1); char* name = new char[län + 1]; name[län] = 0; if (län) empfangen->getNachrichtEncrypted(name, län); Text* tmp = new Text(name); delete[] name; nachricht.sts->teamName->set(tmp, i); } for (int i = 0; i < nachricht.sts->teamAnzahl; i++) { int größe = 0; empfangen->getNachrichtEncrypted((char*)&größe, 4); nachricht.sts->teamSize->set(größe, i); } break; case 7: // SpielErstellt Spieler hinzugefügt empfangen->getNachrichtEncrypted((char*)&nachricht.accountId, 4); break; case 8: // SpielErstellt Spieler entfernt empfangen->getNachrichtEncrypted((char*)&nachricht.accountId, 4); break; case 9: // SpielErstellt Spieler wechselt Team empfangen->getNachrichtEncrypted((char*)&nachricht.accountId, 4); empfangen->getNachrichtEncrypted((char*)&nachricht.spielerNummer, 4); break; case 0xA: // SpielErstellt Chat Nachricht if (1) { char län = 0; empfangen->getNachrichtEncrypted(&län, 1); char* txt = new char[län + 1]; txt[län] = 0; if (län) empfangen->getNachrichtEncrypted(txt, län); nachricht.message = txt; delete[] txt; } break; case 0xB: // Spiel gefunden empfangen->getNachrichtEncrypted((char*)&nachricht.karteId, 4); break; case 0xD: // Spiel Laden Spieler hinzufügen empfangen->getNachrichtEncrypted((char*)&nachricht.accountId, 4); empfangen->getNachrichtEncrypted((char*)&nachricht.spielerNummer, 4); break; case 0xE: // Spiel Laden Spieler Prozent empfangen->getNachrichtEncrypted((char*)&nachricht.accountId, 4); empfangen->getNachrichtEncrypted((char*)&nachricht.prozent, 4); break; case 0xF: // Spiel Laden Spieler Ping empfangen->getNachrichtEncrypted((char*)&nachricht.accountId, 4); empfangen->getNachrichtEncrypted((char*)&nachricht.ping, 4); break; case 0x10: // ping empfangen->sendeEncrypted("\1", 1); break; case 0x12: // Spiel Nachricht empfangen->getNachricht((char*)&nachricht.län, 2); nachricht.data = new char[nachricht.län]; empfangen->getNachricht(nachricht.data, nachricht.län); break; case 0x13: // Statistik Nachricht empfangen->getNachrichtEncrypted((char*)&nachricht.län, 2); nachricht.data = new char[nachricht.län]; empfangen->getNachrichtEncrypted(nachricht.data, nachricht.län); break; case 0x14: // ping empfangen->sendeEncrypted("\1", 1); break; } } while (nachricht.type == 0x10 || nachricht.type == 0x14); return 1; } // Erhält die Verbindung aufrecht // Gibt 1 zurück, falls der Vorgang erfolgreich ist, 0 sonnst // Sollte während einer bestehenden Verbindung etwa einmal alle 60 Sekunden aufgerufen werden, da sonst der Router die Verbindung automatisch trennt bool SpielClient::keepAlive() { if (!senden) return 0; char res = 0; if (!cs.tryLock()) return 1; bool ok = senden->sendeEncrypted("\xF", 1); ok &= senden->getNachrichtEncrypted(&res, 1); cs.unlock(); if (res != 1 || !ok) { err = "Die Verbindung zum Spiel Server ist abgebrochen."; trenne(); return 0; } return res == 1; } // Trennt die Verbindung zum Server // Gibt 1 zurück, falls der Vorgang erfolgreich ist, 0 sonnst // Sollte erst nach einem erfolgreichen Aufruf von verbinde aufgerufen werden bool SpielClient::trenne() { cs.lock(); if (!senden) { cs.unlock(); return 1; } senden->sendeEncrypted("\3", 1); char serverReturn = 0; senden->getNachrichtEncrypted(&serverReturn, 1); senden->trenne(); senden = (Network::Klient*)senden->release(); empfangen->trenne(); empfangen = (Network::Klient*)empfangen->release(); cs.unlock(); return 1; } // Gibt 1 zurück, falls der Client verbunden ist, 0 sonst bool SpielClient::istVerbunden() const { return senden != 0; } // gibt den Letzten Fehlertext zuück // sollte erst aufgerufen werden, nachdem eine andere aufgerufene Methode fehlgeschlagen ist const char* SpielClient::getLetzterFehler() const { return err; }