📄 ladder.c
字号:
/* * Copyright (C) 1999 Rob Crittenden (rcrit@greyoak.com) * Copyright (C) 1999,2000 Ross Combs (rocombs@cs.nmsu.edu) * Copyright (C) 1999,2000 D.Moreaux (vapula@linuxbe.org) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */#define LADDER_INTERNAL_ACCESS#include "common/setup_before.h"#ifdef HAVE_STDDEF_H# include <stddef.h>#else# ifndef NULL# define NULL ((void *)0)# endif#endif#ifdef STDC_HEADERS# include <stdlib.h>#else# ifdef HAVE_MALLOC_H# include <malloc.h># endif#endif#ifdef HAVE_STRING_H# include <string.h>#else# ifdef HAVE_STRINGS_H# include <strings.h># endif#endif#include <errno.h>#include <compat/strerror.h>#include "common/field_sizes.h"#include "account.h"#include "account_wrap.h"#include "common/eventlog.h"#include "common/util.h"#include "game.h"#include "common/tag.h"#include "common/list.h"#include "common/bnettime.h"#include "prefs.h"#include "common/hashtable.h"#include "ladder_calc.h"#include "ladder.h"#include "compat/strcasecmp.h"#include "compat/strncasecmp.h"#include "ladder_binary.h"#include "storage.h"#include "account.h"#include "common/bnet_protocol.h"#include "common/xalloc.h"#include "common/setup_after.h"#define MaxRankKeptInLadder 1000/* for War3 XP computations */static t_xpcalc_entry * xpcalc;static t_xplevel_entry * xplevels;int w3_xpcalc_maxleveldiff;const char * WAR3_solo_file = "WAR3_solo";const char * W3XP_solo_file = "W3XP_solo";const char * WAR3_team_file = "WAR3_team";const char * W3XP_team_file = "W3XP_team";const char * WAR3_ffa_file = "WAR3_ffa";const char * W3XP_ffa_file = "W3XP_ffa";const char * WAR3_at_file = "WAR3_atteam";const char * W3XP_at_file = "W3XP_atteam";const char * STAR_ar_file = "STAR_active_rating";const char * STAR_cr_file = "STAR_current_rating";const char * SEXP_ar_file = "SEXP_active_rating";const char * SEXP_cr_file = "SEXP_current_rating";const char * W2BN_ar_file = "W2BN_active_rating";const char * W2BN_cr_file = "W2BN_current_rating";const char * W2BN_ari_file = "W2BN_active_rating_iron";const char * W2BN_cri_file = "W2BN_current_rating_iron";const char * std_end = ".dat";const char * xml_end = ".xml";char * ladder_id_str[] = {"0","1","","3","","solo","team","ffa"};char * WAR3_solo_filename, * WAR3_team_filename, * WAR3_ffa_filename, * WAR3_at_filename;char * W3XP_solo_filename, * W3XP_team_filename, * W3XP_ffa_filename, * W3XP_at_filename;char * STAR_ar_filename, * STAR_cr_filename, * SEXP_ar_filename, * SEXP_cr_filename;char * W2BN_ar_filename, * W2BN_cr_filename, * W2BN_ari_filename, * W2BN_cri_filename;t_ladder WAR3_solo_ladder, WAR3_team_ladder, WAR3_ffa_ladder, WAR3_at_ladder;t_ladder W3XP_solo_ladder, W3XP_team_ladder, W3XP_ffa_ladder, W3XP_at_ladder;t_ladder STAR_active_rating, STAR_active_wins, STAR_active_games, STAR_current_rating, STAR_current_wins, STAR_current_games;t_ladder SEXP_active_rating, SEXP_active_wins, SEXP_active_games, SEXP_current_rating, SEXP_current_wins, SEXP_current_games;t_ladder W2BN_active_rating, W2BN_active_wins, W2BN_active_games, W2BN_active_rating_ironman, W2BN_active_wins_ironman, W2BN_active_games_ironman;t_ladder W2BN_current_rating, W2BN_current_wins, W2BN_current_games, W2BN_current_rating_ironman, W2BN_current_wins_ironman, W2BN_current_games_ironman;t_ladder_internal * last_internal = NULL;t_ladder * last_ladder = NULL;int last_rank = 0;/* * Make the current ladder statistics the active ones. */extern int ladder_make_active(t_ladder *current, t_ladder *active,int set_attributes);extern int ladderlist_make_all_active(void){ ladder_make_active(ladder_cr(CLIENTTAG_STARCRAFT_UINT,ladder_id_normal), ladder_ar(CLIENTTAG_STARCRAFT_UINT,ladder_id_normal),1); ladder_make_active(ladder_cw(CLIENTTAG_STARCRAFT_UINT,ladder_id_normal), ladder_aw(CLIENTTAG_STARCRAFT_UINT,ladder_id_normal),0); ladder_make_active(ladder_cg(CLIENTTAG_STARCRAFT_UINT,ladder_id_normal), ladder_ag(CLIENTTAG_STARCRAFT_UINT,ladder_id_normal),0); ladder_make_active(ladder_cr(CLIENTTAG_BROODWARS_UINT,ladder_id_normal), ladder_ar(CLIENTTAG_BROODWARS_UINT,ladder_id_normal),1); ladder_make_active(ladder_cw(CLIENTTAG_BROODWARS_UINT,ladder_id_normal), ladder_aw(CLIENTTAG_BROODWARS_UINT,ladder_id_normal),0); ladder_make_active(ladder_cg(CLIENTTAG_BROODWARS_UINT,ladder_id_normal), ladder_ag(CLIENTTAG_BROODWARS_UINT,ladder_id_normal),0); ladder_make_active(ladder_cr(CLIENTTAG_WARCIIBNE_UINT,ladder_id_normal), ladder_ar(CLIENTTAG_WARCIIBNE_UINT,ladder_id_normal),1); ladder_make_active(ladder_cw(CLIENTTAG_WARCIIBNE_UINT,ladder_id_normal), ladder_aw(CLIENTTAG_WARCIIBNE_UINT,ladder_id_normal),0); ladder_make_active(ladder_cg(CLIENTTAG_WARCIIBNE_UINT,ladder_id_normal), ladder_ag(CLIENTTAG_WARCIIBNE_UINT,ladder_id_normal),0); ladder_make_active(ladder_cr(CLIENTTAG_WARCIIBNE_UINT,ladder_id_ironman),ladder_ar(CLIENTTAG_WARCIIBNE_UINT,ladder_id_ironman),1); ladder_make_active(ladder_cw(CLIENTTAG_WARCIIBNE_UINT,ladder_id_ironman),ladder_aw(CLIENTTAG_WARCIIBNE_UINT,ladder_id_ironman),0); ladder_make_active(ladder_cg(CLIENTTAG_WARCIIBNE_UINT,ladder_id_ironman),ladder_ag(CLIENTTAG_WARCIIBNE_UINT,ladder_id_ironman),0); ladder_update_all_accounts(); return 0;}/* * Prepare an account for first ladder play if necessary. */extern int ladder_init_account(t_account * account, t_clienttag clienttag, t_ladder_id id){ int uid; char clienttag_str[5]; if (!account) { eventlog(eventlog_level_error,__FUNCTION__,"got NULL account"); return -1; } if (!clienttag) { eventlog(eventlog_level_error,__FUNCTION__,"got bad clienttag"); return -1; } if (account_get_ladder_rating(account,clienttag,id)==0) { if (account_get_ladder_wins(account,clienttag,id)+ account_get_ladder_losses(account,clienttag,id)>0) /* no ladder games so far... */ { eventlog(eventlog_level_warn,__FUNCTION__,"account for \"%s\" (%s) has %u wins and %u losses but has zero rating",account_get_name(account),clienttag,account_get_ladder_wins(account,clienttag,id),account_get_ladder_losses(account,clienttag,id)); return -1; } account_adjust_ladder_rating(account,clienttag,id,prefs_get_ladder_init_rating()); uid = account_get_uid(account); war3_ladder_add(ladder_cr(clienttag,id),uid,0,account_get_ladder_rating(account,clienttag,id),account,0,clienttag); war3_ladder_add(ladder_cw(clienttag,id),uid,0,0,account,0,clienttag); war3_ladder_add(ladder_cg(clienttag,id),uid,0,0,account,0,clienttag); eventlog(eventlog_level_info,__FUNCTION__,"initialized account for \"%s\" for \"%s\" ladder",account_get_name(account),tag_uint_to_str(clienttag_str,clienttag)); } return 0;}/* * Update player ratings, rankings, etc due to game results. */extern int ladder_update(t_clienttag clienttag, t_ladder_id id, unsigned int count, t_account * * players, t_game_result * results, t_ladder_info * info, t_ladder_option opns){ unsigned int curr; unsigned int winners=0; unsigned int losers=0; unsigned int draws=0; int uid; if (count<1 || count>8) { eventlog(eventlog_level_error,__FUNCTION__,"got invalid player count %u",count); return -1; } if (!players) { eventlog(eventlog_level_error,__FUNCTION__,"got NULL players"); return -1; } if (!results) { eventlog(eventlog_level_error,__FUNCTION__,"got NULL results"); return -1; } if (!clienttag) { eventlog(eventlog_level_error,__FUNCTION__,"got bad clienttag"); return -1; } if (!info) { eventlog(eventlog_level_error,__FUNCTION__,"got NULL info"); return -1; } for (curr=0; curr<count; curr++) { if (!players[curr]) { eventlog(eventlog_level_error,__FUNCTION__,"got NULL player[%u] (of %u)",curr,count); return -1; } switch (results[curr]) { case game_result_win: winners++; break; case game_result_loss: losers++; break; case game_result_draw: draws++; break; case game_result_disconnect: if (opns&ladder_option_disconnectisloss) losers++; break; default: eventlog(eventlog_level_error,__FUNCTION__,"bad results[%u]=%u",curr,(unsigned int)results[curr]); return -1; } } if (draws>0) { if (draws!=count) { eventlog(eventlog_level_error,__FUNCTION__,"some, but not all players had a draw count=%u (winners=%u losers=%u draws=%u)",count,winners,losers,draws); return -1; } return 0; /* no change in case of draw */ } if ((losers<1) || (winners<1) || (winners>1 && (winners!=losers))) { eventlog(eventlog_level_info,__FUNCTION__,"missing winner or loser for count=%u (winners=%u losers=%u draws=%u) - discarding result",count,winners,losers,draws); return 0; } if (ladder_calc_info(clienttag,id,count,players,results,info)<0) { eventlog(eventlog_level_error,__FUNCTION__,"unable to calculate info from game results"); return -1; } for (curr=0; curr<count; curr++) { int won,wins,games; t_account * account; if (results[curr]==game_result_win) won=1; else won=0; account = players[curr]; uid = account_get_uid(account); wins = account_get_ladder_wins(account,clienttag,id); games = wins + account_get_ladder_losses(account,clienttag,id) + account_get_ladder_disconnects(account,clienttag,id); account_adjust_ladder_rating(account,clienttag,id,info[curr].adj); war3_ladder_update(ladder_cr(clienttag,id),uid,won,account_get_ladder_rating(account,clienttag,id),players[curr],0); if (results[curr]!=game_result_draw) war3_ladder_update(ladder_cg(clienttag,id),uid,info[curr].adj,games,players[curr],0); if (results[curr]==game_result_win) war3_ladder_update(ladder_cw(clienttag,id),uid,info[curr].adj,wins,players[curr],0); } ladder_update_all_accounts(); return 0;}extern int ladder_check_map(char const * mapname, t_game_maptype maptype, t_clienttag clienttag){ if (!mapname) { eventlog(eventlog_level_error,__FUNCTION__,"got NULL mapname"); return -1; } if (!clienttag) { eventlog(eventlog_level_error,__FUNCTION__,"got bad clienttag"); return -1; } eventlog(eventlog_level_debug,__FUNCTION__,"checking mapname \"%s\" maptype=%d",mapname,(int)maptype); if (maptype==game_maptype_ladder) /* FIXME: what about Ironman? */ return 1; return 0;}extern t_account * ladder_get_account_by_rank(unsigned int rank, t_ladder_sort lsort, t_ladder_time ltime, t_clienttag clienttag, t_ladder_id id){ unsigned int dummy; if (rank<1) { eventlog(eventlog_level_error,__FUNCTION__,"got zero rank"); return NULL; } if (!clienttag) { eventlog(eventlog_level_error,__FUNCTION__,"got bad clienttag"); return NULL; } switch (lsort) { case ladder_sort_highestrated: if (ltime == ladder_time_current) return ladder_get_account(ladder_cr(clienttag,id),rank,&dummy,clienttag); else return ladder_get_account(ladder_ar(clienttag,id),rank,&dummy,clienttag); case ladder_sort_mostwins: if (ltime == ladder_time_current) return ladder_get_account(ladder_cw(clienttag,id),rank,&dummy,clienttag); else return ladder_get_account(ladder_aw(clienttag,id),rank,&dummy,clienttag); case ladder_sort_mostgames: if (ltime == ladder_time_current) return ladder_get_account(ladder_cg(clienttag,id),rank,&dummy,clienttag); else return ladder_get_account(ladder_ag(clienttag,id),rank,&dummy,clienttag); default: eventlog(eventlog_level_error,__FUNCTION__,"got bad ladder sort %u",(unsigned int)lsort); } return NULL;}extern unsigned int ladder_get_rank_by_account(t_account * account, t_ladder_sort lsort, t_ladder_time ltime, t_clienttag clienttag, t_ladder_id id){ int uid; if (!account) { eventlog(eventlog_level_error,__FUNCTION__,"got NULL account"); return 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -