#include "Spiel.h" #include #ifdef WIN32 #include "..\..\Datenbank\Datenbank.h" #include "..\SpielServer.h" #include "Reader\KartenLeser.h" #else #include "Datenbank.h" #include "SpielServer.h" #include "KartenLeser.h" #include #define Sleep( x ) usleep( (x) * 1000 ) #include #define LoadLibrary( x ) dlopen( (x), RTLD_LAZY ) #define GetProcAddress dlsym #define FreeLibrary dlclose #endif typedef SpielKlasse* (*DllStart)(); // Inhalt der Spiel Klasse aus Spiel.h // Konstruktor Spiel::Spiel(int id, SpielServer* ss) : Thread() { this->ss = ss; this->id = id; klients = new RCArray< SSKlient >(); sts = new SpielerTeamStruktur(); accounts = new Array< int >(); spielerNummern = new Array< int >(); status = new Array< int >(); prozent = new Array< int >(); teamAuswahlFertig = new Array< bool >(); spiel = 0; state = 0; spielerAnzahl = 0; karte = 0; spielDll = 0; statistik = 0; } // Destruktor Spiel::~Spiel() { klients->release(); sts->release(); accounts->release(); spielerNummern->release(); status->release(); prozent->release(); teamAuswahlFertig->release(); if (spiel) spiel->release(); if (statistik) statistik->release(); if (spielDll) FreeLibrary(spielDll); ss->release(); } int Spiel::findFreeTeam() { int free = 0; int teamIndex = 0; int teamSize = sts->teamSize->get(teamIndex); double max = 0; Array< int > teams; for (int i = 0; i < sts->spielerAnzahl; i++) // suche nach teams die prozentual am wenigsten voll sind { bool used = 0; for (int j = 0; j < spielerAnzahl; j++) { if (spielerNummern->hat(j) && spielerNummern->get(j) == i + 1) used = 1; } if (!used) free++; teamSize--; if (!teamSize) { double teamVal = (double)free / sts->teamSize->get(teamIndex); if (teamVal > max) { teams.leeren(); max = teamVal; } if (teamVal >= max) teams.add(teamIndex); free = 0; if (!sts->teamSize->hat(++teamIndex)) break; else teamSize = sts->teamSize->get(teamIndex); } } // suche aus den teams eines zufällig aus double randomVal = rand() / ((double)RAND_MAX + 1); double diff = 1.0 / teams.getEintragAnzahl(); teamIndex = -1; while (randomVal >= 0) { randomVal -= diff; teamIndex++; } if (teams.hat(teamIndex)) return teams.get(teamIndex); else return teams.get(0); } void Spiel::teamAusgleich() { for (int i = 0; i < spielerAnzahl; i++) { int sNum = spielerNummern->hat(i) ? spielerNummern->get(i) : 0; if (!sNum) { int team = findFreeTeam(); for (int j = 0; j < team; j++) sNum += sts->teamSize->get(j); while (true) { sNum++; bool gefunden = 0; for (int k = 0; k < spielerAnzahl; k++) { if (spielerNummern->hat(k) && spielerNummern->get(k) == sNum) { gefunden = 1; break; } } if (!gefunden) break; } while (!spielerNummern->hat(i)) spielerNummern->add(0); spielerNummern->set(sNum, i); } } } // nicht constant void Spiel::setAccounts(int anzahl, Array< int >* zAccounts) { accounts->leeren(); for (int i = 0; i < anzahl; i++) accounts->add(zAccounts->hat(i) ? zAccounts->get(i) : 0); spielerAnzahl = anzahl; } void Spiel::setKlients(int anzahl, RCArray< SSKlient >* zKlients) { klients->leeren(); for (int i = 0; i < anzahl; i++) klients->add(zKlients->get(i)); } void Spiel::setKarteId(int karteId) { karte = karteId; KartenLeser* reader = new KartenLeser(id, karte, dynamic_cast(getThis())); reader->ladeSpielerTeamStruktur(sts); reader->release(); start(); } bool Spiel::klientVerbunden(SSKlient* klient) { int accId = klient->getAccountId(); bool ret = 0; for (int i = 0; i < spielerAnzahl; i++) { if (accounts->hat(i) && accounts->get(i) == accId) { if (state == 1) { klient->erstellungInitialisierung(sts); for (int j = 0; j < spielerAnzahl; j++) { if (accounts->hat(j) && accounts->get(j) != accId) { SSKlient* tmp = klients->z(j); tmp->erstellungAddSpieler(accId); klient->erstellungAddSpieler(accounts->get(j)); if (spielerNummern->hat(j)) klient->erstellungSpielerTeam(accounts->get(j), spielerNummern->get(j)); } } } if (state == 5 && spiel) spiel->klientOnline(klient->getAccountId(), klient); while (!klients->hat(i)) klients->add(0); klients->set(klient, i); while (!status->hat(i)) status->add(0); status->set(1, i); klient->setSpiel(this); ret = 1; break; } } if (!ret) klient->release(); return ret; } bool Spiel::klientWechseltTeam(int accountId, int team) { if (state != 1) return 0; if (team == 0) { for (int i = 0; i < spielerAnzahl; i++) { if (accounts->hat(i) && accounts->get(i) == accountId) { while (!spielerNummern->hat(i)) spielerNummern->add(0); spielerNummern->set(0, i); } SSKlient* tmp = klients->z(i); if (tmp) tmp->erstellungSpielerTeam(accountId, 0); } return 1; } int von = 1; for (int i = 0; i < team - 1; i++) { if (sts->teamSize->hat(i)) von += sts->teamSize->get(i); } int bis = von + (sts->teamSize->hat(team - 1) ? sts->teamSize->get(team - 1) : 0); for (int i = von; i < bis; i++) { bool verwendet = 0; for (int j = 0; j < spielerAnzahl; j++) { if (spielerNummern->hat(j) && spielerNummern->get(j) == i) { verwendet = 1; break; } } if (!verwendet) { for (int j = 0; j < spielerAnzahl; j++) { if (accounts->hat(j) && accounts->get(j) == accountId) { while (!spielerNummern->hat(j)) spielerNummern->add(0); spielerNummern->set(i, j); } SSKlient* tmp = klients->z(j); if (tmp) tmp->erstellungSpielerTeam(accountId, i); } return 1; } } return 0; } bool Spiel::chatNachricht(const char* nachricht) { if (state != 1) return 0; for (int i = 0; i < spielerAnzahl; i++) { SSKlient* tmp = klients->z(i); if (tmp) tmp->erstellungChatNachricht(nachricht); } return 1; } bool Spiel::klientGetrennt(SSKlient* zKlient) { int accId = zKlient->getAccountId(); bool ret = 0; for (int i = 0; i < spielerAnzahl; i++) { if (accounts->hat(i) && accounts->get(i) == accId) { if (status->hat(i) && status->get(i) != 0) { if (state == 1) { for (int j = 0; j < spielerAnzahl; j++) { if (accounts->hat(j) && accounts->get(j) != accId) { SSKlient* tmp = klients->z(j); tmp->erstellungRemoveSpieler(accId); } } } if (state == 5 && spiel) spiel->klientOffline(zKlient->getAccountId()); if (state == 6) { if (statistik) statistik->klientOffline(zKlient->getAccountId()); } zKlient->setSpielErstellt(0); while (!spielerNummern->hat(i)) spielerNummern->add(0); spielerNummern->set(0, i); while (!status->hat(i)) status->add(0); status->set(0, i); while (!klients->hat(i)) klients->add(0); klients->set(0, i); ret = 1; } break; } } return ret; } bool Spiel::klientTeamAuswahlFertig(int accountId) { for (int i = 0; i < spielerAnzahl; i++) { if (accounts->hat(i) && accounts->get(i) == accountId) { while (!teamAuswahlFertig->hat(i)) teamAuswahlFertig->add(0); teamAuswahlFertig->set(1, i); return 1; } } return 0; } bool Spiel::klientBereitZumLaden(int accountId) { if (state != 2) return 0; for (int i = 0; i < spielerAnzahl; i++) { if (accounts->hat(i) && accounts->get(i) == accountId) { while (!status->hat(i)) status->add(0); status->set(2, i); return 1; } } return 0; } bool Spiel::klientSpielLadenProzent(int accountId, int prozent) { if (state != 3 && state != 2) return 0; for (int i = 0; i < spielerAnzahl; i++) { if (accounts->hat(i) && accounts->get(i) == accountId) { while (!this->prozent->hat(i)) this->prozent->add(0); this->prozent->set(prozent, i); return 1; } } return 0; } bool Spiel::klientBereitZumSpiel(int accountId) { if (state != 4) return 0; for (int i = 0; i < spielerAnzahl; i++) { if (accounts->hat(i) && accounts->get(i) == accountId) { while (!status->hat(i)) status->add(0); status->set(3, i); return 1; } } return 0; } bool Spiel::spielNachricht(int accountId, int len, char* bytes) { if (state != 5) return 0; if (spiel) { spiel->nachricht(accountId, len, bytes); return 1; } return 0; } bool Spiel::statistikNachricht(int accountId, int len, char* bytes) { if (state != 6) return 0; if (statistik) { statistik->statistikAnfrage(accountId, (short)len, bytes); return 1; } return 0; } void Spiel::thread() { // Klients aktualisieren for (int i = 0; i < spielerAnzahl; i++) { SSKlient* tmp = klients->z(i); if (tmp) { tmp->setSpielErstellt(0); tmp->setSpiel(this); } } // Vortsetzung senden for (int i = 0; i < spielerAnzahl; i++) { SSKlient* tmp = klients->z(i); if (tmp) tmp->erstellungInitialisierung(sts); } for (int i = 0; i < spielerAnzahl; i++) { SSKlient* tmp = klients->z(i); if (tmp) tmp->erstellungFortsetzen(); } for (int i = 0; i < spielerAnzahl; i++) { SSKlient* tmp = klients->z(i); if (tmp) { for (int j = 0; j < spielerAnzahl; j++) { if (accounts->hat(j)) tmp->erstellungAddSpieler(accounts->get(j)); } } } // warten bis alle ein Team gewählt haben double time = 0; state = 1; ZeitMesser* zeit = new ZeitMesser(); while (time < 40) { zeit->messungStart(); Sleep(100); char verbleibend = (char)(40 - (char)time); bool weiter = 1; for (int i = 0; i < spielerAnzahl; i++) weiter &= teamAuswahlFertig->hat(i) && teamAuswahlFertig->get(i); if (verbleibend < 0 || weiter) { verbleibend = 0; time = 40; } for (int i = 0; i < spielerAnzahl; i++) { SSKlient* tmp = klients->z(i); if (tmp) tmp->zeitVerbleibend(verbleibend); } zeit->messungEnde(); time += zeit->getSekunden(); } // Spielernummern Aufteilen zeit->release(); state = 2; teamAusgleich(); Array< int >* teams = new Array< int >(); for (int i = 0; i < spielerAnzahl; i++) { int sNum = spielerNummern->hat(i) ? spielerNummern->get(i) : 0; int tg = 1; for (int j = 0; j < sts->teamAnzahl; j++) { tg += sts->teamSize->hat(j) ? sts->teamSize->get(j) : 0; if (sNum < tg) { while (!teams->hat(i)) teams->add(0); teams->set(j, i); break; } } } ss->zDB()->spielSetTeams(id, spielerAnzahl, accounts, teams); ss->zDB()->spielSetSpielerNummern(id, spielerAnzahl, accounts, spielerNummern); teams->release(); // Fortsetzung senden for (int i = 0; i < spielerAnzahl; i++) { SSKlient* tmp = klients->z(i); if (tmp) tmp->spielLadenBeginn(); } // Auf bereitschaft warten while (1) { Sleep(100); bool br = 1; for (int i = 0; i < spielerAnzahl; i++) { if (klients->z(i)) br = br && status->hat(i) && status->get(i) == 2; } if (br) break; } // Spieler hinzufügen for (int i = 0; i < spielerAnzahl; i++) spielerNummern->set((spielerNummern->hat(i) ? spielerNummern->get(i) : 0) - 1, i); for (int i = 0; i < spielerAnzahl; i++) { SSKlient* tmp = klients->z(i); if (tmp) { for (int j = 0; j < spielerAnzahl; j++) tmp->spielLadenSpielerAdd(accounts->hat(j) ? accounts->get(j) : 0, spielerNummern->hat(j) ? spielerNummern->get(j) : 0); } } state = 3; // Warten auf laden while (1) { Sleep(1000); bool br = 1; for (int i = 0; i < spielerAnzahl; i++) { SSKlient* tmp = klients->z(i); if (tmp) { int ping = (int)(tmp->ping() * 1000 + 0.5); for (int j = 0; j < spielerAnzahl; j++) { SSKlient* k = klients->z(j); if (k) { k->spielLadenSetSpielerPing(accounts->hat(i) ? accounts->get(i) : 0, ping); k->spielLadenSetSpielerProzent(accounts->hat(i) ? accounts->get(i) : 0, prozent->hat(i) ? prozent->get(i) : 0); } } br = br && prozent->hat(i) && prozent->get(i) == 100; } } if (br) break; } state = 4; // Sende Fortsetzung for (int i = 0; i < spielerAnzahl; i++) { SSKlient* tmp = klients->z(i); if (tmp) tmp->spielLadenFertig(); } // Spiel Initialisieren Text* pfad = new Text(ss->zInit()->zWert("SpielePfad")->getText()); pfad->append("/"); pfad->append(ss->zDB()->getSpielArtId(karte)); pfad->append("/bin/game"); #ifdef WIN32 pfad->append(".dll"); #else pfad->append(".so"); #endif spielDll = LoadLibrary(pfad->getText()); if (!spielDll) { char* err = dlerror(); Text tmp = ss->zInit()->zWert("TempMapPfad")->getText(); tmp += "/"; tmp += id; DateiRemove(tmp); for (int i = 0; i < spielerAnzahl; i++) { SSKlient* tmp = klients->z(i); if (tmp) { tmp->setSpiel(0); tmp->errorZuKlientSende(Text("Fehler beim laden des Spiels: ").operator+(err)); } } ss->zDB()->setSpielStatusBeendet(id, 4); ss->removeSpiel(id); // delete this return; } pfad->release(); DllStart getSpielKlasse = (DllStart)GetProcAddress(spielDll, "getSpielKlasse"); if (!getSpielKlasse) { FreeLibrary(spielDll); spielDll = 0; Text tmp = ss->zInit()->zWert("TempMapPfad")->getText(); tmp += "/"; tmp += id; DateiRemove(tmp); for (int i = 0; i < spielerAnzahl; i++) { SSKlient* tmp = klients->z(i); if (tmp) { tmp->setSpiel(0); tmp->errorZuKlientSende("Fehler beim laden des Spiels. Der Server kann das Spiel nicht finden."); } } ss->zDB()->setSpielStatusBeendet(id, 4); ss->removeSpiel(id); // delete this return; } spiel = getSpielKlasse(); spiel->setPSQLK(dynamic_cast(ss->zDB()->getThis())); spiel->setSpielId(id); spiel->setKarteId(karte); Text tmp = ss->zInit()->zWert("TempMapPfad")->getText(); tmp += "/"; tmp += id; spiel->setTempPfad(tmp); spiel->setAccounts(spielerAnzahl, accounts); spiel->setKlients(spielerAnzahl, (RCArray< SSKlientV > *)klients); spiel->setSpielerNummern(spielerAnzahl, spielerNummern); // auf klients warten while (1) { Sleep(100); bool br = 1; for (int i = 0; i < spielerAnzahl; i++) { if (klients->z(i)) br = br && status->hat(i) && status->get(i) == 3; } if (br) break; } // Spiel starten state = 5; ss->zDB()->setSpielStatusIsRunning(id); spiel->run(); // Spiel ist zuende state = 6; statistik = spiel->getStatistik(); spiel = (SpielKlasse*)spiel->release(); statistik->run(); // Statistik ist zuende state = 7; statistik = (StatistikV*)statistik->release(); FreeLibrary(spielDll); spielDll = 0; DateiRemove(tmp); for (int i = 0; i < spielerAnzahl; i++) { SSKlient* tmp = klients->z(i); if (tmp) tmp->setSpiel(0); } ss->removeSpiel(id); // delete this } // constant int Spiel::getId() const { return id; } int Spiel::getSpielerNummer(int accountId) const { for (int i = 0; i < spielerAnzahl; i++) { if (accounts->hat(i) && accounts->get(i) == accountId) return spielerNummern->hat(i) ? spielerNummern->get(i) : 0; } return 0; }