/** * @brief Responds with teaminfo such as free team num * @sa CL_ParseTeamInfoMessage */ static void SVC_TeamInfo (struct net_stream *s) { client_t *cl; dbuffer msg; char infoGlobal[MAX_INFO_STRING] = ""; NET_WriteByte(&msg, clc_oob); NET_WriteRawString(&msg, "teaminfo\n"); Info_SetValueForKey(infoGlobal, sizeof(infoGlobal), "sv_teamplay", Cvar_GetString("sv_teamplay")); Info_SetValueForKey(infoGlobal, sizeof(infoGlobal), "sv_maxteams", Cvar_GetString("sv_maxteams")); Info_SetValueForKey(infoGlobal, sizeof(infoGlobal), "sv_maxplayersperteam", Cvar_GetString("sv_maxplayersperteam")); NET_WriteString(&msg, infoGlobal); cl = NULL; while ((cl = SV_GetNextClient(cl)) != NULL) { if (cl->state >= cs_connected) { char infoPlayer[MAX_INFO_STRING] = ""; /* show players that already have a team with their teamnum */ int teamId = svs.ge->ClientGetTeamNum(cl->player); if (!teamId) teamId = TEAM_NO_ACTIVE; Info_SetValueForKeyAsInteger(infoPlayer, sizeof(infoPlayer), "cl_team", teamId); Info_SetValueForKeyAsInteger(infoPlayer, sizeof(infoPlayer), "cl_ready", svs.ge->ClientIsReady(cl->player)); Info_SetValueForKey(infoPlayer, sizeof(infoPlayer), "cl_name", cl->name); NET_WriteString(&msg, infoPlayer); } } NET_WriteByte(&msg, 0); NET_WriteMsg(s, msg); }
/** * @brief Set the used team for the given player * @param[out] player The player the team should be set for * @param[in] team The team to set for the given player * @return <code>true</code> if the team was set successfully, <code>false</code> otherwise. */ bool G_SetTeamForPlayer (player_t* player, const int team) { assert(player); assert(team >= TEAM_NO_ACTIVE && team < MAX_TEAMS); if (G_IsAIPlayer(player)) { if (team != TEAM_ALIEN && team != TEAM_CIVILIAN) return false; } else { if (!sv_teamplay->integer) { player_t *p = NULL; while ((p = G_PlayerGetNextHuman(p)) != NULL) { if (p->pers.team == team) return false; } } } player->pers.team = team; /* if we started in dev mode, we maybe don't have a * starting position in this map */ if (!g_nospawn->integer) { if (team >= 0 && team < MAX_TEAMS) { if (!level.num_spawnpoints[team]) gi.Error("No spawnpoints for team %i", team); } } if (!G_IsAIPlayer(player)) Info_SetValueForKeyAsInteger(player->pers.userinfo, sizeof(player->pers.userinfo), "cl_team", team); return true; }
/** * @brief Responds with teaminfo such as free team num * @sa CL_ParseTeamInfoMessage */ static void SVC_TeamInfo (struct net_stream* s) { if (SVC_RateLimitAddress(*s)) { Com_DPrintf(DEBUG_SERVER, "SVC_TeamInfo: rate limit from %s exceeded, dropping request\n", NET_StreamToString(s)); return; } /* Allow getinfo to be DoSed relatively easily, but prevent excess outbound bandwidth usage when being flooded inbound */ if (SVC_RateLimit(&outboundLeakyBucket)) { Com_DPrintf(DEBUG_SERVER, "SVC_TeamInfo: rate limit exceeded, dropping request\n"); return; } char infoGlobal[MAX_INFO_STRING] = ""; Info_SetValueForKey(infoGlobal, sizeof(infoGlobal), "sv_teamplay", Cvar_GetString("sv_teamplay")); Info_SetValueForKey(infoGlobal, sizeof(infoGlobal), "sv_maxteams", Cvar_GetString("sv_maxteams")); Info_SetValueForKey(infoGlobal, sizeof(infoGlobal), "sv_maxplayersperteam", Cvar_GetString("sv_maxplayersperteam")); dbuffer msg; NET_WriteByte(&msg, svc_oob); NET_WriteRawString(&msg, "teaminfo\n"); NET_WriteString(&msg, infoGlobal); client_t* cl = nullptr; while ((cl = SV_GetNextClient(cl)) != nullptr) { if (cl->state < cs_connected) continue; char infoPlayer[MAX_INFO_STRING] = ""; /* show players that already have a team with their teamnum */ int teamId = svs.ge->ClientGetTeamNum(*cl->player); if (!teamId) teamId = TEAM_NO_ACTIVE; Info_SetValueForKeyAsInteger(infoPlayer, sizeof(infoPlayer), "cl_team", teamId); Info_SetValueForKeyAsInteger(infoPlayer, sizeof(infoPlayer), "cl_ready", svs.ge->ClientIsReady(cl->player)); Info_SetValueForKey(infoPlayer, sizeof(infoPlayer), "cl_name", cl->name); NET_WriteString(&msg, infoPlayer); } NET_WriteByte(&msg, 0); NET_WriteMsg(s, msg); }
/** * @brief Responds with short info for broadcast scans * @note The second parameter should be the current protocol version number. * @note Only a short server description - the user can determine whether he is * interested in a full status * @sa CL_ParseStatusMessage * @sa CL_ProcessPingReply */ static void SVC_Info (struct net_stream* s) { if (SVC_RateLimitAddress(*s)) { Com_DPrintf(DEBUG_SERVER, "SVC_Info: rate limit from %s exceeded, dropping request\n", NET_StreamToString(s)); return; } /* Allow getinfo to be DoSed relatively easily, but prevent excess outbound bandwidth usage when being flooded inbound */ if (SVC_RateLimit(&outboundLeakyBucket)) { Com_DPrintf(DEBUG_SERVER, "SVC_Info: rate limit exceeded, dropping request\n"); return; } if (sv_maxclients->integer == 1) { Com_DPrintf(DEBUG_SERVER, "Ignore info string in singleplayer mode\n"); return; /* ignore in single player */ } const int version = atoi(Cmd_Argv(1)); if (version != PROTOCOL_VERSION) { char string[MAX_VAR]; Com_sprintf(string, sizeof(string), "%s: wrong version (client: %i, host: %i)\n", sv_hostname->string, version, PROTOCOL_VERSION); NET_OOB_Printf(s, SV_CMD_PRINT "\n%s", string); return; } int count = 0; client_t* cl = nullptr; while ((cl = SV_GetNextClient(cl)) != nullptr) if (cl->state >= cs_spawning) count++; char infostring[MAX_INFO_STRING]; infostring[0] = '\0'; Info_SetValueForKey(infostring, sizeof(infostring), "sv_protocol", DOUBLEQUOTE(PROTOCOL_VERSION)); Info_SetValueForKey(infostring, sizeof(infostring), "sv_hostname", sv_hostname->string); Info_SetValueForKey(infostring, sizeof(infostring), "sv_dedicated", sv_dedicated->string); Info_SetValueForKey(infostring, sizeof(infostring), "sv_gametype", sv_gametype->string); Info_SetValueForKey(infostring, sizeof(infostring), "sv_mapname", sv->name); Info_SetValueForKeyAsInteger(infostring, sizeof(infostring), "clients", count); Info_SetValueForKey(infostring, sizeof(infostring), "sv_maxclients", sv_maxclients->string); Info_SetValueForKey(infostring, sizeof(infostring), "sv_version", UFO_VERSION); NET_OOB_Printf(s, SV_CMD_INFO "\n%s", infostring); }
/** * @brief Responds with short info for broadcast scans * @note The second parameter should be the current protocol version number. * @note Only a short server description - the user can determine whether he is * interested in a full status * @sa CL_ParseStatusMessage * @sa CL_ProcessPingReply */ static void SVC_Info (struct net_stream *s) { int version; if (sv_maxclients->integer == 1) { Com_DPrintf(DEBUG_SERVER, "Ignore info string in singleplayer mode\n"); return; /* ignore in single player */ } version = atoi(Cmd_Argv(1)); if (version != PROTOCOL_VERSION) { char string[MAX_VAR]; Com_sprintf(string, sizeof(string), "%s: wrong version (client: %i, host: %i)\n", sv_hostname->string, version, PROTOCOL_VERSION); NET_OOB_Printf(s, "print\n%s", string); } else { client_t *cl; char infostring[MAX_INFO_STRING]; int count = 0; cl = NULL; while ((cl = SV_GetNextClient(cl)) != NULL) if (cl->state >= cs_spawning) count++; infostring[0] = '\0'; Info_SetValueForKey(infostring, sizeof(infostring), "sv_protocol", DOUBLEQUOTE(PROTOCOL_VERSION)); Info_SetValueForKey(infostring, sizeof(infostring), "sv_hostname", sv_hostname->string); Info_SetValueForKey(infostring, sizeof(infostring), "sv_dedicated", sv_dedicated->string); Info_SetValueForKey(infostring, sizeof(infostring), "sv_gametype", sv_gametype->string); Info_SetValueForKey(infostring, sizeof(infostring), "sv_mapname", sv->name); Info_SetValueForKeyAsInteger(infostring, sizeof(infostring), "clients", count); Info_SetValueForKey(infostring, sizeof(infostring), "sv_maxclients", sv_maxclients->string); Info_SetValueForKey(infostring, sizeof(infostring), "sv_version", UFO_VERSION); NET_OOB_Printf(s, "info\n%s", infostring); } }