/** * @brief called whenever the player updates a userinfo variable. * @note The game can override any of the settings in place (forcing skins or names, etc) before copying it off. */ void G_ClientUserinfoChanged (player_t * player, const char *userinfo) { const bool alreadyReady = player->isReady; const int oldTeamnum = Info_IntegerForKey(player->pers.userinfo, "cl_teamnum"); /* check for malformed or illegal info strings */ if (!Info_Validate(userinfo)) userinfo = "\\cl_name\\badinfo"; /* set name */ Q_strncpyz(player->pers.netname, Info_ValueForKey(userinfo, "cl_name"), sizeof(player->pers.netname)); Q_strncpyz(player->pers.userinfo, userinfo, sizeof(player->pers.userinfo)); player->autostand = Info_IntegerForKey(userinfo, "cl_autostand"); player->reactionLeftover = Info_IntegerForKey(userinfo, "cl_reactionleftover"); player->isReady = Info_IntegerForKey(userinfo, "cl_ready"); /* send the updated config string */ gi.ConfigString(CS_PLAYERNAMES + player->num, "%s", player->pers.netname); /* try to update to the preferred team */ if (!G_MatchIsRunning() && oldTeamnum != Info_IntegerForKey(userinfo, "cl_teamnum")) { /* if the player is marked as ready he can't change his team */ if (!alreadyReady || !player->isReady) { player->pers.team = TEAM_NO_ACTIVE; G_GetTeam(player); } else { Com_DPrintf(DEBUG_GAME, "G_ClientUserinfoChanged: player %s is already marked as being ready\n", player->pers.netname); } } }
/** * @brief Parsed the server ping response. * @param[out] server The server data to store the parsed information in * @param[in] msg The ping response with the server information to parse * @sa CL_PingServerCallback * @sa SVC_Info * @return @c true if the server is compatible, @c msg is not @c null and the server * wasn't pinged already, @c false otherwise */ static bool CL_ProcessPingReply (serverList_t *server, const char *msg) { if (!msg) return false; if (PROTOCOL_VERSION != Info_IntegerForKey(msg, "sv_protocol")) { Com_DPrintf(DEBUG_CLIENT, "CL_ProcessPingReply: Protocol mismatch\n"); return false; } if (!Q_streq(UFO_VERSION, Info_ValueForKey(msg, "sv_version"))) { Com_DPrintf(DEBUG_CLIENT, "CL_ProcessPingReply: Version mismatch\n"); } if (server->pinged) return false; server->pinged = true; Q_strncpyz(server->sv_hostname, Info_ValueForKey(msg, "sv_hostname"), sizeof(server->sv_hostname)); Q_strncpyz(server->version, Info_ValueForKey(msg, "sv_version"), sizeof(server->version)); Q_strncpyz(server->mapname, Info_ValueForKey(msg, "sv_mapname"), sizeof(server->mapname)); Q_strncpyz(server->gametype, Info_ValueForKey(msg, "sv_gametype"), sizeof(server->gametype)); server->clients = Info_IntegerForKey(msg, "clients"); server->sv_dedicated = Info_IntegerForKey(msg, "sv_dedicated"); server->sv_maxclients = Info_IntegerForKey(msg, "sv_maxclients"); return true; }
/** * @brief Team selection text * * This function fills the multiplayer_selectteam menu with content * @sa NET_OOB_Printf * @sa SVC_TeamInfo * @sa CL_SelectTeam_Init_f */ void CL_ParseTeamInfoMessage (dbuffer *msg) { char str[4096]; int cnt = 0; linkedList_t *userList = NULL; linkedList_t *userTeam = NULL; if (cgi->NET_ReadString(msg, str, sizeof(str)) == 0) { cgi->UI_ResetData(TEXT_MULTIPLAYER_USERLIST); cgi->UI_ResetData(TEXT_MULTIPLAYER_USERTEAM); cgi->UI_ExecuteConfunc("multiplayer_playerNumber 0"); cgi->Com_DPrintf(DEBUG_CLIENT, "CL_ParseTeamInfoMessage: No teaminfo string\n"); return; } OBJZERO(teamData); teamData.maxteams = Info_IntegerForKey(str, "sv_maxteams"); teamData.maxPlayersPerTeam = Info_IntegerForKey(str, "sv_maxplayersperteam"); /* for each lines */ while (cgi->NET_ReadString(msg, str, sizeof(str)) > 0) { const int team = Info_IntegerForKey(str, "cl_team"); const int isReady = Info_IntegerForKey(str, "cl_ready"); const char *user = Info_ValueForKey(str, "cl_name"); if (team > 0 && team < MAX_TEAMS) teamData.teamCount[team]++; /* store data */ cgi->LIST_AddString(&userList, user); if (team != TEAM_NO_ACTIVE) cgi->LIST_AddString(&userTeam, va(_("Team %d"), team)); else cgi->LIST_AddString(&userTeam, _("No team")); cgi->UI_ExecuteConfunc("multiplayer_playerIsReady %i %i", cnt, isReady); cnt++; } cgi->UI_RegisterLinkedListText(TEXT_MULTIPLAYER_USERLIST, userList); cgi->UI_RegisterLinkedListText(TEXT_MULTIPLAYER_USERTEAM, userTeam); cgi->UI_ExecuteConfunc("multiplayer_playerNumber %i", cnt); /* no players are connected ATM */ if (!cnt) { /** @todo warning must not be into the player list. * if we see this we are the first player that would be connected to the server */ /* Q_strcat(teamData.teamInfoText, _("No player connected\n"), sizeof(teamData.teamInfoText)); */ } cgi->Cvar_SetValue("mn_maxteams", teamData.maxteams); cgi->Cvar_SetValue("mn_maxplayersperteam", teamData.maxPlayersPerTeam); }
/** * @brief Pull specific info from a newly changed userinfo string into a more C friendly form. */ void SV_UserinfoChanged (client_t* cl) { /* call prog code to allow overrides */ { const ScopedMutex scopedMutex(svs.serverMutex); svs.ge->ClientUserinfoChanged(*cl->player, cl->userinfo); } /* name of the player */ Q_strncpyz(cl->name, Info_ValueForKey(cl->userinfo, "cl_name"), sizeof(cl->name)); /* mask off high bit */ for (int i = 0; i < sizeof(cl->name); i++) cl->name[i] &= 127; /* msg command */ cl->messagelevel = Info_IntegerForKey(cl->userinfo, "cl_msg"); Com_DPrintf(DEBUG_SERVER, "SV_UserinfoChanged: Changed userinfo for player %s\n", cl->name); }
/** * @brief Returns the preferred team number for the player */ int G_ClientGetTeamNumPref (const player_t * player) { assert(player); return Info_IntegerForKey(player->pers.userinfo, "cl_teamnum"); }