#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; ref = 1; } // 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; } spielerNummern->set( sNum, i ); } } } // nicht constant void Spiel::setAccounts( int anzahl, Array< int > *zAccounts ) { for( int i = 0; i < anzahl; i++ ) accounts->set( zAccounts->hat( i ) ? zAccounts->get( i ) : 0, i ); spielerAnzahl = anzahl; } void Spiel::setKlients( int anzahl, RCArray< SSKlient > *zKlients ) { for( int i = 0; i < anzahl; i++ ) klients->set( zKlients->get( i ), i ); } void Spiel::setKarteId( int karteId ) { karte = karteId; KartenLeser *reader = new KartenLeser( id, karte, ss->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 ); klients->set( klient, i ); 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 ) 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 ) spielerNummern->set( i, j ); SSKlient *tmp = klients->z( j ); if( tmp ) tmp->erstellungSpielerTeam( accountId, i ); } return 1; } } return 0; } bool Spiel::chatNachricht( 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 ); spielerNummern->set( 0, i ); status->set( 0, i ); 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 ) { 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 ) { 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 ) { 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 ) { 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 ) { 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 ) { // error } pfad->release(); DllStart getSpielKlasse = (DllStart)GetProcAddress( spielDll, "getSpielKlasse" ); if( !getSpielKlasse ) { // error } spiel = getSpielKlasse(); spiel->setPSQLK( 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 = spiel->release(); statistik->run(); // Statistik ist zuende state = 7; statistik = statistik->release(); FreeLibrary( spielDll ); spielDll = 0; DateiRemove( tmp ); 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; } // Reference Counting Spiel *Spiel::getThis() { ref++; return this; } Spiel *Spiel::release() { ref--; if( !ref ) delete this; return 0; }