X-Git-Url: https://de.git.xonotic.org/?a=blobdiff_plain;f=qcsrc%2Fserver%2Fcommand%2Fcmd.qc;h=c4e85e28ef55d37debee2e5fc81c9da48ae7b419;hb=6018d119b3c9f4e54d6d21f6339948708c83d83f;hp=f218a4e6705fa9eafc27f19ef1b8cc4157eb0054;hpb=75d933b9020f991f01bc73d0041d12dc8733d952;p=xonotic%2Fxonotic-data.pk3dir.git diff --git a/qcsrc/server/command/cmd.qc b/qcsrc/server/command/cmd.qc index f218a4e67..c4e85e28e 100644 --- a/qcsrc/server/command/cmd.qc +++ b/qcsrc/server/command/cmd.qc @@ -1,11 +1,11 @@ // ========================================================= // Server side networked commands code, reworked by Samual -// Last updated: December 26th, 2011 +// Last updated: December 28th, 2011 // ========================================================= float SV_ParseClientCommand_floodcheck() { - if (timeoutStatus != 2) // if the game is not paused... but wait, doesn't that mean it could be dos'd by pausing it? eh? (old code) + if not(timeout_status) // not while paused { if(time <= (self.cmd_floodtime + autocvar_sv_clientcommand_antispam_time)) { @@ -32,12 +32,16 @@ void ClientCommand_autoswitch(float request, float argc) { case CMD_REQUEST_COMMAND: { - self.autoswitch = InterpretBoolean(argv(1)); - sprint(self, strcat("^1autoswitch is currently turned ", (self.autoswitch ? "on" : "off"), ".\n")); - return; // never fall through to usage + if(argv(1) != "") + { + self.autoswitch = InterpretBoolean(argv(1)); + sprint(self, strcat("^1autoswitch is currently turned ", (self.autoswitch ? "on" : "off"), ".\n")); + return; + } } default: + sprint(self, "Incorrect parameters for ^2autoswitch^7\n"); case CMD_REQUEST_USAGE: { sprint(self, "\nUsage:^3 cmd autoswitch selection\n"); @@ -59,6 +63,7 @@ void ClientCommand_checkfail(float request, string command) // internal command, } default: + sprint(self, "Incorrect parameters for ^2checkfail^7\n"); case CMD_REQUEST_USAGE: { sprint(self, "\nUsage:^3 cmd checkfail \n"); @@ -74,29 +79,34 @@ void ClientCommand_clientversion(float request, float argc) // internal command, { case CMD_REQUEST_COMMAND: { - if(self.flags & FL_CLIENT) + if(argv(1) != "") { - self.version = ((argv(1) == "$gameversion") ? 1 : stof(argv(1))); - - if(self.version < autocvar_gameversion_min || self.version > autocvar_gameversion_max) + if(self.flags & FL_CLIENT) { - self.version_mismatch = 1; - ClientKill_TeamChange(-2); // observe - } - else if(autocvar_g_campaign || autocvar_g_balance_teams || autocvar_g_balance_teams_force) - { - //JoinBestTeam(self, FALSE, TRUE); - } - else if(teamplay && !autocvar_sv_spectate && !(self.team_forced > 0)) - { - self.classname = "observer"; // really? - stuffcmd(self, "menu_showteamselect\n"); + self.version = ((argv(1) == "$gameversion") ? 1 : stof(argv(1))); + + if(self.version < autocvar_gameversion_min || self.version > autocvar_gameversion_max) + { + self.version_mismatch = 1; + ClientKill_TeamChange(-2); // observe + } + else if(autocvar_g_campaign || autocvar_g_balance_teams || autocvar_g_balance_teams_force) + { + //JoinBestTeam(self, FALSE, TRUE); + } + else if(teamplay && !autocvar_sv_spectate && !(self.team_forced > 0)) + { + self.classname = "observer"; // really? + stuffcmd(self, "menu_showteamselect\n"); + } } + + return; } - return; // never fall through to usage } default: + sprint(self, "Incorrect parameters for ^2clientversion^7\n"); case CMD_REQUEST_USAGE: { sprint(self, "\nUsage:^3 cmd clientversion version\n"); @@ -106,29 +116,33 @@ void ClientCommand_clientversion(float request, float argc) // internal command, } } -void ClientCommand_getmapvotepic(float request, float argc) // internal command, used only by code +void ClientCommand_mv_getpicture(float request, float argc) // internal command, used only by code { switch(request) { case CMD_REQUEST_COMMAND: { - if(intermission_running) - MapVote_SendPicture(stof(argv(1))); + if(argv(1) != "") + { + if(intermission_running) + MapVote_SendPicture(stof(argv(1))); - return; // never fall through to usage + return; + } } default: + sprint(self, "Incorrect parameters for ^2mv_getpicture^7\n"); case CMD_REQUEST_USAGE: { - sprint(self, "\nUsage:^3 cmd getmapvotepic mapid\n"); + sprint(self, "\nUsage:^3 cmd mv_getpicture mapid\n"); sprint(self, " Where 'mapid' is the id number of the map to request an image of on the map vote selection menu.\n"); return; } } } -void ClientCommand_join(float request) // legacy +void ClientCommand_join(float request) { switch(request) { @@ -138,7 +152,7 @@ void ClientCommand_join(float request) // legacy { if(self.classname != "player" && !lockteams && !g_arena) { - if(nJoinAllowed(1)) + if(nJoinAllowed(self)) { if(g_ca) { self.caplayer = 1; } if(autocvar_g_campaign) { campaign_bots_may_start = 1; } @@ -192,7 +206,7 @@ void ClientCommand_ready(float request) // todo: anti-spam for toggling readynes } // cannot reset the game while a timeout is active! - if(!timeoutStatus) + if not(timeout_status) ReadyCount(); } else { sprint(self, "^1Game has already been restarted\n"); @@ -212,34 +226,6 @@ void ClientCommand_ready(float request) // todo: anti-spam for toggling readynes } } -void ClientCommand_reportcvar(float request, float argc, string command) -{ - switch(request) - { - case CMD_REQUEST_COMMAND: - { - float tokens; - string s; - - if(substring(argv(2), 0, 1) == "$") // undefined cvar: use the default value on the server then - { - s = strcat(substring(command, argv_start_index(0), argv_end_index(1) - argv_start_index(0)), " \"", cvar_defstring(argv(1)), "\""); - tokens = tokenize_console(s); - } - GetCvars(1); - return; // never fall through to usage - } - - default: - case CMD_REQUEST_USAGE: - { - sprint(self, "\nUsage:^3 cmd reportcvar \n"); - sprint(self, " Where 'cvar' is the cvar plus arguments to send to the server.\n"); - return; - } - } -} - void ClientCommand_say(float request, float argc, string command) { switch(request) @@ -286,49 +272,52 @@ void ClientCommand_selectteam(float request, float argc) { case CMD_REQUEST_COMMAND: { - float selection; - - if (self.flags & FL_CLIENT) + if(argv(1) != "") { - if(teamplay) - if not(self.team_forced > 0) - if not(lockteams) - { - switch(argv(1)) + if(self.flags & FL_CLIENT) + { + if(teamplay) + if not(self.team_forced > 0) + if not(lockteams) { - case "red": selection = COLOR_TEAM1; break; - case "blue": selection = COLOR_TEAM2; break; - case "yellow": selection = COLOR_TEAM3; break; - case "pink": selection = COLOR_TEAM4; break; - case "auto": selection = (-1); break; + float selection; - default: break; - } - - if(selection) - { - if(self.team == selection && self.deadflag == DEAD_NO) - sprint(self, "^7You already are on that team.\n"); - else if(self.wasplayer && autocvar_g_changeteam_banned) - sprint(self, "^1You cannot change team, forbidden by the server.\n"); - else - ClientKill_TeamChange(selection); + switch(argv(1)) + { + case "red": selection = COLOR_TEAM1; break; + case "blue": selection = COLOR_TEAM2; break; + case "yellow": selection = COLOR_TEAM3; break; + case "pink": selection = COLOR_TEAM4; break; + case "auto": selection = (-1); break; + + default: selection = 0; break; + } + + if(selection) + { + if(self.team == selection && self.deadflag == DEAD_NO) + sprint(self, "^7You already are on that team.\n"); + else if(self.wasplayer && autocvar_g_changeteam_banned) + sprint(self, "^1You cannot change team, forbidden by the server.\n"); + else + ClientKill_TeamChange(selection); + } } - } + else + sprint(self, "^7The game has already begun, you must wait until the next map to be able to join a team.\n"); else - sprint(self, "^7The game has already begun, you must wait until the next map to be able to join a team.\n"); + sprint(self, "^7selectteam can not be used as your team is forced\n"); else - sprint(self, "^7selectteam can not be used as your team is forced\n"); - else - sprint(self, "^7selectteam can only be used in teamgames\n"); + sprint(self, "^7selectteam can only be used in teamgames\n"); + } + return; } - return; // never fall through to usage } default: + sprint(self, "Incorrect parameters for ^2selectteam^7\n"); case CMD_REQUEST_USAGE: { - //sprint(self, strcat( "selectteam none/red/blue/yellow/pink/auto - \"", argv(1), "\" not recognised\n" ) ); sprint(self, "\nUsage:^3 cmd selectteam team\n"); sprint(self, " Where 'team' is the prefered team to try and join.\n"); sprint(self, " Full list of options here: \"red, blue, yellow, pink, auto\"\n"); @@ -343,11 +332,15 @@ void ClientCommand_selfstuff(float request, string command) { case CMD_REQUEST_COMMAND: { - stuffcmd(self, substring(command, argv_start_index(1), argv_end_index(-1) - argv_start_index(1))); - return; // never fall through to usage + if(argv(1) != "") + { + stuffcmd(self, substring(command, argv_start_index(1), argv_end_index(-1) - argv_start_index(1))); + return; + } } default: + sprint(self, "Incorrect parameters for ^2selectteam^7\n"); case CMD_REQUEST_USAGE: { sprint(self, "\nUsage:^3 cmd selfstuff \n"); @@ -363,19 +356,25 @@ void ClientCommand_sentcvar(float request, float argc, string command) { case CMD_REQUEST_COMMAND: { - float tokens; - string s; - - if(argc == 2) // undefined cvar: use the default value on the server then + if(argv(1) != "") { - s = strcat(substring(command, argv_start_index(0), argv_end_index(1) - argv_start_index(0)), " \"", cvar_defstring(argv(1)), "\""); - tokens = tokenize_console(s); + //float tokens; + string s; + + if(argc == 2) // undefined cvar: use the default value on the server then + { + s = strcat(substring(command, argv_start_index(0), argv_end_index(1) - argv_start_index(0)), " \"", cvar_defstring(argv(1)), "\""); + tokenize_console(s); + } + + GetCvars(1); + + return; } - GetCvars(1); - return; // never fall through to usage } default: + sprint(self, "Incorrect parameters for ^2sentcvar^7\n"); case CMD_REQUEST_USAGE: { sprint(self, "\nUsage:^3 cmd sentcvar \n"); @@ -385,7 +384,7 @@ void ClientCommand_sentcvar(float request, float argc, string command) } } -void ClientCommand_spectate(float request) // legacy +void ClientCommand_spectate(float request) { switch(request) { @@ -412,7 +411,7 @@ void ClientCommand_spectate(float request) // legacy if(self.classname == "player" && autocvar_sv_spectate == 1) ClientKill_TeamChange(-2); // observe - // in CA, allow a dead player to move to spectatators (without that, caplayer!=0 will be moved back to the player list) + // in CA, allow a dead player to move to spectators (without that, caplayer!=0 will be moved back to the player list) // note: if arena game mode is ever done properly, this needs to be removed. if(g_ca && self.caplayer && (self.classname == "spectator" || self.classname == "observer")) { @@ -439,11 +438,15 @@ void ClientCommand_suggestmap(float request, float argc) { case CMD_REQUEST_COMMAND: { - sprint(self, strcat(MapVote_Suggest(argv(1)), "\n")); - return; // never fall through to usage + if(argv(1) != "") + { + sprint(self, strcat(MapVote_Suggest(argv(1)), "\n")); + return; + } } default: + sprint(self, "Incorrect parameters for ^2suggestmap^7\n"); case CMD_REQUEST_USAGE: { sprint(self, "\nUsage:^3 cmd suggestmap map\n"); @@ -461,21 +464,21 @@ void ClientCommand_tell(float request, float argc, string command) { if(argc >= 3) { - entity tell_to = GetFilteredEntity(argv(1)); + entity tell_to = GetIndexedEntity(argc, 1); float tell_accepted = VerifyClientEntity(tell_to, TRUE, FALSE); if(tell_accepted > 0) // the target is a real client { if(tell_to != self) // and we're allowed to send to them :D { - Say(self, FALSE, tell_to, substring(command, argv_start_index(2), argv_end_index(-1) - argv_start_index(2)), TRUE); + Say(self, FALSE, tell_to, substring(command, argv_start_index(next_token), argv_end_index(-1) - argv_start_index(next_token)), TRUE); return; } else { print_to(self, "You can't ^2tell^7 a message to yourself."); return; } } - else if(strtolower(argv(1)) == "world") + else if(argv(1) == "#0") { - trigger_magicear_processmessage_forallears(self, -1, world, substring(command, argv_start_index(ParseCommandPlayerSlotTarget_firsttoken), argv_end_index(-1) - argv_start_index(ParseCommandPlayerSlotTarget_firsttoken))); + trigger_magicear_processmessage_forallears(self, -1, world, substring(command, argv_start_index(next_token), argv_end_index(-1) - argv_start_index(next_token))); return; } else { print_to(self, strcat("tell: ", GetClientErrorString(tell_accepted, argv(1)), ".")); return; } @@ -493,20 +496,25 @@ void ClientCommand_tell(float request, float argc, string command) } } -void ClientCommand_voice(float request, float argc, string command) // legacy +void ClientCommand_voice(float request, float argc, string command) { switch(request) { case CMD_REQUEST_COMMAND: { - if(argc >= 3) - VoiceMessage(argv(1), substring(command, argv_start_index(2), argv_end_index(-1) - argv_start_index(2))); - else - VoiceMessage(argv(1), ""); - return; // never fall through to usage + if(argv(1) != "") + { + if(argc >= 3) + VoiceMessage(argv(1), substring(command, argv_start_index(2), argv_end_index(-1) - argv_start_index(2))); + else + VoiceMessage(argv(1), ""); + + return; + } } default: + sprint(self, "Incorrect parameters for ^2voice^7\n"); case CMD_REQUEST_USAGE: { sprint(self, "\nUsage:^3 cmd voice messagetype \n"); @@ -546,24 +554,13 @@ void ClientCommand_(float request) // ===================================== // Do not hard code aliases for these, instead create them in commands.cfg... also: keep in alphabetical order, please ;) -// Common commands have double indentation to separate them a bit. #define CLIENT_COMMANDS(request,arguments,command) \ CLIENT_COMMAND("autoswitch", ClientCommand_autoswitch(request, arguments), "Whether or not to switch automatically when getting a better weapon") \ CLIENT_COMMAND("checkfail", ClientCommand_checkfail(request, command), "Report if a client-side check failed") \ CLIENT_COMMAND("clientversion", ClientCommand_clientversion(request, arguments), "Release version of the game") \ - CLIENT_COMMAND("cvar_changes", CommonCommand_cvar_changes(request, self), "Prints a list of all changed server cvars") \ - CLIENT_COMMAND("cvar_purechanges", CommonCommand_cvar_purechanges(request, self), "Prints a list of all changed gameplay cvars") \ - CLIENT_COMMAND("getmapvotepic", ClientCommand_getmapvotepic(request, arguments), "Retrieve mapshot picture from the server") \ - CLIENT_COMMAND("info", CommonCommand_info(request, self, arguments), "Request for unique server information set up by admin") \ + CLIENT_COMMAND("mv_getpicture", ClientCommand_mv_getpicture(request, arguments), "Retrieve mapshot picture from the server") \ CLIENT_COMMAND("join", ClientCommand_join(request), "Become a player in the game") \ - CLIENT_COMMAND("ladder", CommonCommand_ladder(request, self), "Get information about top players if supported") \ - CLIENT_COMMAND("lsmaps", CommonCommand_lsmaps(request, self), "List maps which can be used with the current game mode") \ - CLIENT_COMMAND("lsnewmaps", CommonCommand_lsnewmaps(request, self), "List maps which have no records or are seemingly unplayed yet") \ - CLIENT_COMMAND("maplist", CommonCommand_maplist(request, self), "Display full server maplist reply") \ - CLIENT_COMMAND("rankings", CommonCommand_rankings(request, self), "Print information about rankings") \ CLIENT_COMMAND("ready", ClientCommand_ready(request), "Qualify as ready to end warmup stage (or restart server if allowed)") \ - CLIENT_COMMAND("records", CommonCommand_records(request, self), "List top 10 records for the current map") \ - CLIENT_COMMAND("reportcvar", ClientCommand_reportcvar(request, arguments, command), "Old system for sending a client cvar to the server") \ CLIENT_COMMAND("say", ClientCommand_say(request, arguments, command), "Print a message to chat to all players") \ CLIENT_COMMAND("say_team", ClientCommand_say_team(request, arguments, command), "Print a message to chat to all team mates") \ CLIENT_COMMAND("selectteam", ClientCommand_selectteam(request, arguments), "Attempt to choose a team to join into") \ @@ -571,20 +568,14 @@ void ClientCommand_(float request) CLIENT_COMMAND("sentcvar", ClientCommand_sentcvar(request, arguments, command), "New system for sending a client cvar to the server") \ CLIENT_COMMAND("spectate", ClientCommand_spectate(request), "Become an observer") \ CLIENT_COMMAND("suggestmap", ClientCommand_suggestmap(request, arguments), "Suggest a map to the mapvote at match end") \ - CLIENT_COMMAND("teamstatus", CommonCommand_teamstatus(request, self), "Show information about player and team scores") \ CLIENT_COMMAND("tell", ClientCommand_tell(request, arguments, command), "Send a message directly to a player") \ - CLIENT_COMMAND("time", CommonCommand_time(request, self), "Print different formats/readouts of time") \ - CLIENT_COMMAND("timein", CommonCommand_timein(request, self), "Resume the game from being paused with a timeout") \ - CLIENT_COMMAND("timeout", CommonCommand_timeout(request, self), "Call a timeout which pauses the game for certain amount of time unless unpaused") \ CLIENT_COMMAND("voice", ClientCommand_voice(request, arguments, command), "Send voice message via sound") \ - CLIENT_COMMAND("vote", VoteCommand(request, self, arguments, command), "Request an action to be voted upon by players") \ - CLIENT_COMMAND("who", CommonCommand_who(request, self, arguments), "Display detailed client information about all players") \ /* nothing */ void ClientCommand_macro_help() { #define CLIENT_COMMAND(name,function,description) \ - { print(" ^2", name, "^7: ", description, "\n"); } + { sprint(self, " ^2", name, "^7: ", description, "\n"); } CLIENT_COMMANDS(0, 0, "") #undef CLIENT_COMMAND @@ -603,17 +594,27 @@ float ClientCommand_macro_command(float argc, string command) return FALSE; } -float ClientCommand_macro_usage(float argc, string command) +float ClientCommand_macro_usage(float argc) { #define CLIENT_COMMAND(name,function,description) \ { if(name == strtolower(argv(1))) { function; return TRUE; } } - CLIENT_COMMANDS(CMD_REQUEST_USAGE, argc, command) + CLIENT_COMMANDS(CMD_REQUEST_USAGE, argc, "") #undef CLIENT_COMMAND return FALSE; } +void ClientCommand_macro_write_aliases(float fh) +{ + #define CLIENT_COMMAND(name,function,description) \ + { CMD_Write_Alias("qc_cmd_cmd", name, description); } + + CLIENT_COMMANDS(0, 0, "") + #undef CLIENT_COMMAND + + return; +} // ====================================== // Main Function Called By Engine (cmd) @@ -622,8 +623,17 @@ float ClientCommand_macro_usage(float argc, string command) void SV_ParseClientCommand(string command) { + // if we're banned, don't even parse the command + if(Ban_MaybeEnforceBanOnce(self)) + return; + float argc = tokenize_console(command); + // for the mutator hook system + cmd_name = strtolower(argv(0)); + cmd_argc = argc; + cmd_string = command; + // Guide for working with argc arguments by example: // argc: 1 - 2 - 3 - 4 // argv: 0 - 1 - 2 - 3 @@ -635,10 +645,9 @@ void SV_ParseClientCommand(string command) // exempt commands which are not subject to floodcheck case "begin": break; // handled by engine in host_cmd.c case "download": break; // handled by engine in cl_parse.c - case "getmapvotepic": break; // handled by server in this file + case "mv_getpicture": break; // handled by server in this file case "pause": break; // handled by engine in host_cmd.c case "prespawn": break; // handled by engine in host_cmd.c - case "reportcvar": break; // handled by server in this file case "sentcvar": break; // handled by server in this file case "spawn": break; // handled by engine in host_cmd.c @@ -646,25 +655,34 @@ void SV_ParseClientCommand(string command) if(SV_ParseClientCommand_floodcheck()) break; // "TRUE": continue, as we're not flooding yet else - return print("^1ERROR: ^7ANTISPAM CAUGHT: ", command, ".\n"); // "FALSE": not allowed to continue, halt + return; // "FALSE": not allowed to continue, halt // print("^1ERROR: ^7ANTISPAM CAUGHT: ", command, ".\n"); } - /* NOTE: totally disabled for now for bandwidth/security reasons, however the functionality and descriptions are there if we ever want it. + /* NOTE: should this be disabled? It can be spammy perhaps, but hopefully it's okay for now */ if(argv(0) == "help") { if(argc == 1) { - sprint(self, "\nUsage:^3 cmd COMMAND...^7, where possible commands are:\n"); - ClientCommand_macro_help; - sprint(self, "For help about specific commands, type cmd help COMMAND\n"); + sprint(self, "\nClient networked commands:\n"); + ClientCommand_macro_help(); + + sprint(self, "\nCommon networked commands:\n"); + CommonCommand_macro_help(self); + + sprint(self, "\nUsage:^3 cmd COMMAND...^7, where possible commands are listed above.\n"); + sprint(self, "For help about a specific command, type cmd help COMMAND\n"); return; } - else if(ClientCommand_macro_usage(argc, command)) // Instead of trying to call a command, we're going to see detailed information about it + else if(CommonCommand_macro_usage(argc, self)) // Instead of trying to call a command, we're going to see detailed information about it + { + return; + } + else if(ClientCommand_macro_usage(argc)) // same, but for normal commands now { return; } } - else*/ if(MUTATOR_CALLHOOK(SV_ParseClientCommand)) + else if(MUTATOR_CALLHOOK(SV_ParseClientCommand)) { return; // handled by a mutator } @@ -672,10 +690,14 @@ void SV_ParseClientCommand(string command) { return; // handled by server/cheats.qc } + else if(CommonCommand_macro_command(argc, self, command)) + { + return; // handled by server/command/common.qc + } else if(ClientCommand_macro_command(argc, command)) // continue as usual and scan for normal commands { return; // handled by one of the above ClientCommand_* functions } else clientcommand(self, command); -} \ No newline at end of file +}