Topic: Помогите поправить.
Суть проблемы:
На гхост боте стата ДОТЫ считается с помощью приложения update_dota_elo, исходники этого приложения вшиты в сервер PVPGN. То есть update_dota_elo считает стату и отправляет её в базу данных не GHOSTBOT а PVPGN. Проблема в том, что когда новый игрок зашедший на сервер играет игру и после игры, когда подсчитывается его стата, то всё работает без проблем. То есть ему выдаются птс. К примеру было у него 1000 птс, а стало 1100. А когда этот же игрок играет вторую игру, птс может не засчитать после окончания этой игры, так же и третью, четвертую... В чём суть проблемы я толком не понял.
Я пробовал удалять данные о птс очках своих игроков и заново запускать подсчёт статистики для всех игр, после повторного подсчёте некоторые игры, которые раннее не были засчитаны - засчитались!
Ошибка при засчёте других игр в основном "gameid [chislo] has more than 10 players, ignoring" хотя игроков в игре всегда 10.
Я думаю так, dota_elo записывает без проблем игры, если в игре игроки, не имеющие в базе данных не одной игры, то есть новые игроки, а если игрок имеет хотя бы 1 игру, то dota_elo не засчитывает этого игрока.
[img]geekpic.net/dt-2R7JX2.jpg[/img]
gameid 25 - игра не засчитана. Тут всё верно, в игре нет выигравшей команды.
gameid 26 - тут тоже самое.
gameid 27 - игра засчитана.
А если поднять чуть выше, то тут:
[img]geekpic.net/dt-63LLA9.jpg[/img]
gameid 23 - найдены новые игроки, как и в gameid 27, но птс не засчитывает.
В общем такая передряга. Может в коде что-нибудь поправить?
bool elothreadstatus = true;
extern unsigned long __stdcall EloThread( void * arg1 )
{
string CFGFile = ".\\update_dota_elo.cfg";
CIniReader CFG( CFGFile.c_str( ) );
string Server = CFG.ReadString( "DotaElo" , "db_mysql_server" , "127.0.0.1" );
string Database = CFG.ReadString( "DotaElo" , "db_mysql_database" , "ghost" );
string User = CFG.ReadString( "DotaElo" , "db_mysql_user" , "root" );
string Password = CFG.ReadString( "DotaElo" , "db_mysql_password" , "" );
int Port = CFG.ReadInteger( "DotaElo" , "db_mysql_port" , 0 );
eventlog( eventlog_level_debug , __FUNCTION__ , "-> %s" ,"connecting to database server" );
MYSQL *Connection = NULL;
if ( !( Connection = mysql_init( NULL ) ) )
{
eventlog( eventlog_level_error , __FUNCTION__ , "-> %s" , mysql_error( Connection ));
elothread = NULL;
return 0;
}
my_bool Reconnect = true;
mysql_options( Connection , MYSQL_OPT_RECONNECT , &Reconnect );
if ( !( mysql_real_connect( Connection , Server.c_str( ) , User.c_str( ) , Password.c_str( ) , Database.c_str( ) , Port , NULL , 0 ) ) )
{
eventlog( eventlog_level_error , __FUNCTION__ , "-> %s" , mysql_error( Connection ) );
elothread = NULL;
return 0;
}
while ( true )
{
if ( !elothreadstatus )
{
mysql_close( Connection );
elothread = NULL;
elothreadstatus = true;
ExitThread( 0 );
return 0;
}
Sleep( 5000 );
cout << "connected" << endl;
cout << "beginning transaction" << endl;
string QBegin = "BEGIN";
if ( mysql_real_query( Connection , QBegin.c_str( ) , QBegin.size( ) ) != 0 )
{
eventlog( eventlog_level_error , __FUNCTION__ , "-> %s" , mysql_error( Connection ) );
elothread = NULL;
Sleep( 1000 );
return 0;
}
cout << "creating tables" << endl;
string QCreate1 = "CREATE TABLE IF NOT EXISTS dota_elo_scores ( id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, name VARCHAR(15) NOT NULL, server VARCHAR(100) NOT NULL, score REAL NOT NULL, streak INT NOT NULL , leaves INT UNSIGNED NOT NULL )";
string QCreate2 = "CREATE TABLE IF NOT EXISTS dota_elo_games_scored ( id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, gameid INT NOT NULL )";
if ( mysql_real_query( Connection , QCreate1.c_str( ) , QCreate1.size( ) ) != 0 )
{
eventlog( eventlog_level_error , __FUNCTION__ , "-> %s" , mysql_error( Connection ) );
elothread = NULL;
Sleep( 1000 );
return 0;
}
if ( mysql_real_query( Connection , QCreate2.c_str( ) , QCreate2.size( ) ) != 0 )
{
eventlog( eventlog_level_error , __FUNCTION__ , "-> %s" , mysql_error( Connection ) );
elothread = NULL;
Sleep( 1000 );
return 0;
}
cout << "getting unscored games" << endl;
queue<GamesStr> UnscoredGames;
string QSelectUnscored = "SELECT id, duration, gamename FROM games WHERE id NOT IN ( SELECT gameid FROM dota_elo_games_scored ) ORDER BY id";
if ( mysql_real_query( Connection , QSelectUnscored.c_str( ) , QSelectUnscored.size( ) ) != 0 )
{
eventlog( eventlog_level_error , __FUNCTION__ , "-> %s" , mysql_error( Connection ) );
elothread = NULL;
Sleep( 1000 );
return 0;
}
else
{
MYSQL_RES *Result = mysql_store_result( Connection );
if ( Result )
{
vector<string> Row = MySQLFetchRow( Result );
while ( Row.size( ) == 3 )
{
GamesStr tmpgmstr;
tmpgmstr.gameid = UTIL_ToUInt32( Row[ 0 ].c_str( ) );
tmpgmstr.duration = UTIL_ToUInt32( Row[ 1 ].c_str( ) );
tmpgmstr.gamename = Row[ 2 ];
UnscoredGames.push( tmpgmstr );
Row = MySQLFetchRow( Result );
}
mysql_free_result( Result );
}
else
{
eventlog( eventlog_level_error , __FUNCTION__ , "-> %s" , mysql_error( Connection ) );
elothread = NULL;
Sleep( 1000 );
return 0;
}
}
cout << "found " << UnscoredGames.size( ) << " unscored games" << endl;
while ( !UnscoredGames.empty( ) )
{
Sleep( 2000 );
GamesStr curgamestr = UnscoredGames.front( );
unsigned int GameID = curgamestr.gameid;
UnscoredGames.pop( );
string QSelectPlayers = "SELECT dota_elo_scores.id, gameplayers.name, spoofedrealm, newcolour, winner, score, streak, leaves, gameplayers.left FROM dotaplayers LEFT JOIN dotagames ON dotagames.gameid=dotaplayers.gameid LEFT JOIN gameplayers ON gameplayers.gameid=dotaplayers.gameid AND gameplayers.colour=dotaplayers.colour LEFT JOIN dota_elo_scores ON dota_elo_scores.name=gameplayers.name AND server=spoofedrealm WHERE dotaplayers.gameid=" + UTIL_ToString( GameID );
if ( mysql_real_query( Connection , QSelectPlayers.c_str( ) , QSelectPlayers.size( ) ) != 0 )
{
eventlog( eventlog_level_error , __FUNCTION__ , "-> %s" , mysql_error( Connection ) );
elothread = NULL;
Sleep( 1000 );
return 0;
}
else
{
MYSQL_RES *Result = mysql_store_result( Connection );
if ( Result )
{
cout << "gameid " << UTIL_ToString( GameID ) << " found" << endl;
bool ignore = false;
unsigned int rowids[ 10 ];
string names[ 10 ];
string servers[ 10 ];
t_account * playeraccounts[ 10 ];
bool exists[ 10 ];
int num_players = 0;
float player_ratings[ 10 ];
int player_teams[ 10 ];
int player_streaks[ 10 ];
unsigned int player_leaves[ 10 ];
int num_teams = 2;
float team_ratings[ 2 ];
float team_winners[ 2 ];
int team_numplayers[ 2 ];
team_ratings[ 0 ] = 0.0;
team_ratings[ 1 ] = 0.0;
team_numplayers[ 0 ] = 0;
team_numplayers[ 1 ] = 0;
vector<string> Row = MySQLFetchRow( Result );
while ( Row.size( ) == 9 )
{
if ( num_players = 0 )
{
cout << "gameid " << UTIL_ToString( GameID ) << " has more than 10 players, ignoring" << endl;
ignore = true;
break;
}
unsigned int Winner = UTIL_ToUInt32( Row[ 4 ].c_str( ) );
if ( Winner != 1 && Winner != 2 )
{
cout << "gameid " << UTIL_ToString( GameID ) << " has no winner, ignoring" << endl;
ignore = true;
break;
}
else if ( Winner == 1 )
{
team_winners[ 0 ] = 1.0;
team_winners[ 1 ] = 0.0;
}
else
{
team_winners[ 0 ] = 0.0;
team_winners[ 1 ] = 1.0;
}
if ( !Row[ 0 ].empty( ) )
rowids[ num_players ] = UTIL_ToUInt32( Row[ 0 ].c_str( ) );
else
rowids[ num_players ] = 0;
names[ num_players ] = Row[ 1 ];
servers[ num_players ] = Row[ 2 ];
t_account * curplacc;
if ( !( curplacc = accountlist_find_account( names[ num_players ].c_str( ) ) ) )
{
playeraccounts[ num_players ] = NULL;
if ( !Row[ 5 ].empty( ) )
{
exists[ num_players ] = true;
player_ratings[ num_players ] = UTIL_ToFloat( Row[ 5 ].c_str( ) );
}
else
{
cout << "new player [" << Row[ 1 ] << "] found" << endl;
exists[ num_players ] = false;
player_ratings[ num_players ] = 1000.0;
}
if ( !Row[ 6 ].empty( ) )
{
player_streaks[ num_players ] = UTIL_ToInt32( Row[ 6 ].c_str( ) );
}
else
{
player_streaks[ num_players ] = 0;
}
if ( !Row[ 7 ].empty( ) )
{
player_leaves[ num_players ] = UTIL_ToUInt32( Row[ 7 ].c_str( ) );
}
else
{
player_leaves[ num_players ] = 0;
}
}
else
{
playeraccounts[ num_players ] = curplacc;
player_ratings[ num_players ] = account_get_pts( curplacc );
player_streaks[ num_players ] = account_get_streak( curplacc );
player_leaves[ num_players ] = account_get_leaves( curplacc );
}
if ( !Row[ 8 ].empty( ) )
{
uint32_t playerleft = UTIL_ToInt32( Row[ 8 ].c_str( ) );
if ( curgamestr.duration - playerleft > 5 * 60 )
player_leaves[ num_players ]++;
}
unsigned int Colour = UTIL_ToUInt32( Row[ 3 ].c_str( ) );
if ( Colour >= 1 && Colour <= 5 )
{
player_teams[ num_players ] = 0;
team_ratings[ 0 ] += player_ratings[ num_players ];
team_numplayers[ 0 ]++;
}
else if ( Colour >= 7 && Colour <= 11 )
{
player_teams[ num_players ] = 1;
team_ratings[ 1 ] += player_ratings[ num_players ];
team_numplayers[ 1 ]++;
}
else
{
cout << "gameid " << UTIL_ToString( GameID ) << " has a player with an invalid newcolour, ignoring" << endl;
ignore = true;
break;
}
if ( team_winners[ player_teams[ num_players ] ] == 1.0 )
{
if ( player_streaks[ num_players ] < 0 )
player_streaks[ num_players ] = 1;
else
player_streaks[ num_players ] ++;
}
else
{
if ( player_streaks[ num_players ] > 0 )
player_streaks[ num_players ] = -1;
else
player_streaks[ num_players ] --;
}
num_players++;
Row = MySQLFetchRow( Result );
}
mysql_free_result( Result );
if ( curgamestr.duration < 60 * 5 )
{
for ( int i = 0; i < num_players; i++ )
{
char * tempmessage = new char[ MAX_MESSAGE_LEN ];
snprintf( tempmessage , MAX_MESSAGE_LEN , " Game %s - ignored! Duration < 5 min!" , curgamestr.gamename.c_str( ) );
sendmsgforplayername( tempmessage , names[ i ].c_str( ) );
delete[ ] tempmessage;
}
ignore = true;
}
if ( !ignore )
{
if ( num_players == 0 )
cout << "gameid " << UTIL_ToString( GameID ) << " has no players, ignoring" << endl;
else if ( team_numplayers[ 0 ] == 0 )
cout << "gameid " << UTIL_ToString( GameID ) << " has no Sentinel players, ignoring" << endl;
else if ( team_numplayers[ 1 ] == 0 )
cout << "gameid " << UTIL_ToString( GameID ) << " has no Scourge players, ignoring" << endl;
else
{
cout << "gameid " << UTIL_ToString( GameID ) << " is calculating" << endl;
float old_player_ratings[ 10 ];
memcpy( old_player_ratings , player_ratings , sizeof( float ) * 10 );
team_ratings[ 0 ] /= team_numplayers[ 0 ];
team_ratings[ 1 ] /= team_numplayers[ 1 ];
elo_recalculate_ratings( num_players , player_ratings , player_teams , num_teams , team_ratings , player_leaves , player_streaks , team_winners );
for ( int i = 0; i < num_players; i++ )
{
cout << "player [" << names[ i ] << "] rating " << UTIL_ToString( ( unsigned int ) old_player_ratings[ i ] ) << " -> " << UTIL_ToString( ( unsigned int ) player_ratings[ i ] ) << endl;
if ( exists[ i ] )
{
string QUpdateScore;//= "UPDATE dota_elo_scores SET score=" + UTIL_ToString( player_ratings[ i ] , 2 ) + " WHERE id=" + UTIL_ToString( rowids[ i ] );
QUpdateScore = "UPDATE dota_elo_scores SET score=" + UTIL_ToString( player_ratings[ i ] , 2 ) + ", streak=" + UTIL_ToString( player_streaks[ i ] ) + ", leaves=" + UTIL_ToString( player_leaves[ i ] ) + " WHERE id=" + UTIL_ToString( rowids[ i ] );
if ( mysql_real_query( Connection , QUpdateScore.c_str( ) , QUpdateScore.size( ) ) != 0 )
{
eventlog( eventlog_level_error , __FUNCTION__ , "-> %s" , mysql_error( Connection ) );
elothread = NULL;
Sleep( 1000 );
return 0;
}
}
else
{
string EscName = MySQLEscapeString( Connection , names[ i ] );
string EscServer = MySQLEscapeString( Connection , servers[ i ] );
string QInsertScore; //= "INSERT INTO dota_elo_scores ( name, server, score ) VALUES ( '" + EscName + "', '" + EscServer + "', " + UTIL_ToString( player_ratings[ i ] , 2 ) + " )";
QInsertScore = "INSERT INTO dota_elo_scores ( name, server, score, streak, leaves ) VALUES ( '" + EscName + "', '" + EscServer + "', " + UTIL_ToString( player_ratings[ i ] , 2 ) + ", " + UTIL_ToString( player_streaks[ i ] ) + ", " + UTIL_ToString( player_leaves[ i ] ) + " )";
if ( mysql_real_query( Connection , QInsertScore.c_str( ) , QInsertScore.size( ) ) != 0 )
{
eventlog( eventlog_level_error , __FUNCTION__ , "-> %s" , mysql_error( Connection ) );
elothread = NULL;
Sleep( 1000 );
return 0;
}
}
if ( playeraccounts[ i ] != NULL )
{
int oldptsvar = account_get_pts( playeraccounts[ i ] );
char * newstateinf = new char[ MAX_MESSAGE_LEN ];
snprintf( newstateinf , MAX_MESSAGE_LEN , "Player:%s , OLD PTS:%d , NEW PTS:%d" , account_get_name( playeraccounts[ i ] ) , oldptsvar , account_get_pts( playeraccounts[ i ] ) );
LadderLogAddText( newstateinf );
delete[ ]newstateinf;
account_set_pts( playeraccounts[ i ] , player_ratings[ i ] );
account_set_leaves( playeraccounts[ i ] , player_leaves[ i ] );
if ( team_winners[ player_teams[ i ] ] == 1.0 )
{
//unsigned int playerminstreak = account_get_minstreak( playeraccounts[ i ] );
int playermaxstreak = account_get_maxstreak( playeraccounts[ i ] );
int playerstreak = account_get_streak( playeraccounts[ i ] );
if ( playerstreak < 0 )
playerstreak = 1;
else
playerstreak++;
if ( playermaxstreak < playerstreak )
playermaxstreak = playerstreak;
account_set_maxstreak( playeraccounts[ i ] , playermaxstreak );
account_set_streak( playeraccounts[ i ] , playerstreak );
account_set_wins( playeraccounts[ i ] , account_get_wins( playeraccounts[ i ] ) + 1 );
t_connection * tempplcn;
if ( !( tempplcn = account_get_conn( playeraccounts[ i ] ) ) )
;
else
{
char * tempmsgc = new char[ MAX_MESSAGE_LEN ];
snprintf( tempmsgc , MAX_MESSAGE_LEN , " You new stats-> Streak:%d , Wins:%u, Looses:%u, Pts:%d" , account_get_streak( playeraccounts[ i ] ) , account_get_wins( playeraccounts[ i ] ) , account_get_looses( playeraccounts[ i ] ) , account_get_pts( playeraccounts[ i ] ) );
sendmsgforplayername( tempmsgc , names[ i ].c_str( ) );
delete[ ] tempmsgc;
}
}
else
{
account_set_looses( playeraccounts[ i ] , account_get_looses( playeraccounts[ i ] ) + 1 );
int playerminstreak = account_get_minstreak( playeraccounts[ i ] );
int playerstreak = account_get_streak( playeraccounts[ i ] );
if ( playerstreak > 0 )
playerstreak = -1;
else
playerstreak--;
if ( playerminstreak > playerstreak )
playerminstreak = playerstreak;
account_set_minstreak( playeraccounts[ i ] , playerminstreak );
account_set_streak( playeraccounts[ i ] , playerstreak );
}
}
}
}
}
}
else
{
eventlog( eventlog_level_error , __FUNCTION__ , "-> %s" , mysql_error( Connection ) );
elothread = NULL;
Sleep( 1000 );
return 0;
}
}
string QInsertScored = "INSERT INTO dota_elo_games_scored ( gameid ) VALUES ( " + UTIL_ToString( GameID ) + " )";
if ( mysql_real_query( Connection , QInsertScored.c_str( ) , QInsertScored.size( ) ) != 0 )
{
eventlog( eventlog_level_error , __FUNCTION__ , "-> %s" , mysql_error( Connection ) );
elothread = NULL;
Sleep( 1000 );
return 0;
}
}
cout << "copying dota elo scores to scores table" << endl;
string QCopyScores1 = "DELETE FROM scores WHERE category='dota_elo'";
string QCopyScores2;//= "INSERT INTO scores ( category, name, server, score ) SELECT 'dota_elo', name, server, score FROM dota_elo_scores";
QCopyScores2 = "INSERT INTO scores ( category, name, server, score, streak, leaves ) SELECT 'dota_elo', name, server, score, streak, leaves FROM dota_elo_scores";
if ( mysql_real_query( Connection , QCopyScores1.c_str( ) , QCopyScores1.size( ) ) != 0 )
{
eventlog( eventlog_level_error , __FUNCTION__ , "-> %s" , mysql_error( Connection ) );
elothread = NULL;
Sleep( 1000 );
return 0;
}
if ( mysql_real_query( Connection , QCopyScores2.c_str( ) , QCopyScores2.size( ) ) != 0 )
{
eventlog( eventlog_level_error , __FUNCTION__ , "-> %s" , mysql_error( Connection ) );
elothread = NULL;
Sleep( 1000 );
return 0;
}
cout << "committing transaction" << endl;
string QCommit = "COMMIT";
if ( mysql_real_query( Connection , QCommit.c_str( ) , QCommit.size( ) ) != 0 )
{
eventlog( eventlog_level_error , __FUNCTION__ , "-> %s" , mysql_error( Connection ) );
elothread = NULL;
Sleep( 1000 );
return 0;
}
cout << "done" << endl;
}
return 0;
}
}
}
Это кусок кода, где по команде /start происходит коннект к базе данных, чекаются новые игры, и подсчитываются.
Если Вам интересно, могу скинуть целый код.