Here's how I went about tracing the code, if you're interested. I still don't have a definite answer for you, but maybe someone can take it from here.
Game code side:
http://xonotic.org/tools/cacs/#0a/0/stats.xon
Code:
grep -R "g_playerstats_gamereport_uri" **/*.qc -B 2
data/xonotic-data.pk3dir/qcsrc/common/playerstats.qc- });
data/xonotic-data.pk3dir/qcsrc/common/playerstats.qc-
data/xonotic-data.pk3dir/qcsrc/common/playerstats.qc: if(autocvar_g_playerstats_gamereport_uri != "")
--
data/xonotic-data.pk3dir/qcsrc/common/playerstats.qc- PlayerStats_GameReport_DelayMapVote = true;
data/xonotic-data.pk3dir/qcsrc/common/playerstats.qc- url_multi_fopen(
data/xonotic-data.pk3dir/qcsrc/common/playerstats.qc: autocvar_g_playerstats_gamereport_uri,
--
data/xonotic-data.pk3dir/qcsrc/common/playerstats.qc-void PlayerStats_GameReport_Init() // initiated before InitGameplayMode so that scores are added properly
data/xonotic-data.pk3dir/qcsrc/common/playerstats.qc-{
data/xonotic-data.pk3dir/qcsrc/common/playerstats.qc: if(autocvar_g_playerstats_gamereport_uri == "") { return; }
Code:
grep -R "url_multi_fopen" **/*.qc
data/xonotic-data.pk3dir/qcsrc/common/playerstats.qc: url_multi_fopen(
data/xonotic-data.pk3dir/qcsrc/lib/urllib.qc:void url_multi_fopen(string url, int mode, url_ready_func rdy, entity pass)
data/xonotic-data.pk3dir/qcsrc/lib/urllib.qc: LOG_INFO("url_multi_fopen: need at least one URL\n");
data/xonotic-data.pk3dir/qcsrc/server/weapons/weaponstats.qc: url_multi_fopen(autocvar_sv_weaponstats_file, FILE_APPEND, WeaponStats_ready, NULL);
Code:
grep -R "void url_single_fopen" **/*.qc -n
data/xonotic-data.pk3dir/qcsrc/lib/urllib.qc:85:void url_single_fopen(string url, int mode, url_ready_func rdy, entity pass)
XonStat Side:
(accepting a POST request).
https://github.com/antzucaro/XonStat/blo...n.py#L1047
Stats are sent over TCP. There is no redundancy, though that would be nice. At best retry logic on the server-side could be implemented.