X-Git-Url: https://de.git.xonotic.org/?a=blobdiff_plain;f=host_cmd.c;h=cfa9bb3fcf9eb49e9f53677d4f6eb49d1a78afd6;hb=d3e2f7e92ec8883147b70a7bc0971a7b4561d3d5;hp=f5f5fcc44ba9cb47b6afc90d26499b3251e19fd0;hpb=c9b0fa32db0baecaf6d6b4f30dbb5042c24515b1;p=xonotic%2Fdarkplaces.git diff --git a/host_cmd.c b/host_cmd.c index f5f5fcc4..cfa9bb3f 100644 --- a/host_cmd.c +++ b/host_cmd.c @@ -22,6 +22,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. int current_skill; cvar_t sv_cheats = {0, "sv_cheats", "0", "enables cheat commands in any game, and cheat impulses in dpmod"}; +cvar_t rcon_password = {0, "rcon_password", "", "password to authenticate rcon commands"}; +cvar_t rcon_address = {0, "rcon_address", "", "server address to send rcon commands to (when not connected to a server)"}; qboolean allowcheats = false; /* @@ -278,11 +280,7 @@ void Host_Map_f (void) strcpy(level, Cmd_Argv(1)); SV_SpawnServer(level); if (sv.active && cls.state == ca_disconnected) - { - SV_VM_Begin(); CL_EstablishConnection("local:1"); - SV_VM_End(); - } } /* @@ -301,16 +299,16 @@ void Host_Changelevel_f (void) Con_Print("changelevel : continue game on a new level\n"); return; } - // HACKHACKHACK - if (!sv.active) { - Host_Map_f(); - return; - } if (cls.demoplayback) { Con_Print("Only the server may changelevel\n"); return; } + // HACKHACKHACK + if (!sv.active) { + Host_Map_f(); + return; + } if (cmd_source != src_command) return; @@ -325,11 +323,7 @@ void Host_Changelevel_f (void) strcpy(level, Cmd_Argv(1)); SV_SpawnServer(level); if (sv.active && cls.state == ca_disconnected) - { - SV_VM_Begin(); CL_EstablishConnection("local:1"); - SV_VM_End(); - } } /* @@ -348,7 +342,7 @@ void Host_Restart_f (void) Con_Print("restart : restart current level\n"); return; } - if (!sv.active || cls.demoplayback) + if (!sv.active) { Con_Print("Only the server may restart\n"); return; @@ -364,11 +358,7 @@ void Host_Restart_f (void) strcpy(mapname, sv.name); SV_SpawnServer(mapname); if (sv.active && cls.state == ca_disconnected) - { - SV_VM_Begin(); CL_EstablishConnection("local:1"); - SV_VM_End(); - } } /* @@ -381,22 +371,39 @@ This is sent just before a server changes levels */ void Host_Reconnect_f (void) { - if (cmd_source == src_command) + if (cls.protocol == PROTOCOL_QUAKEWORLD) { - Con_Print("reconnect is not valid from the console\n"); - return; - } - if (Cmd_Argc() != 1) - { - Con_Print("reconnect : wait for signon messages again\n"); - return; + if (cls.qw_downloadmemory) // don't change when downloading + return; + + S_StopAllSounds(); + + if (cls.netcon) + { + if (cls.state == ca_connected && cls.signon < SIGNONS) + { + Con_Printf("reconnecting...\n"); + MSG_WriteChar(&cls.netcon->message, qw_clc_stringcmd); + MSG_WriteString(&cls.netcon->message, "new"); + } + else + Con_Printf("Please use connect instead (reconnect not implemented)\n"); + } } - if (!cls.signon) + else { - //Con_Print("reconnect: no signon, ignoring reconnect\n"); - return; + if (Cmd_Argc() != 1) + { + Con_Print("reconnect : wait for signon messages again\n"); + return; + } + if (!cls.signon) + { + Con_Print("reconnect: no signon, ignoring reconnect\n"); + return; + } + cls.signon = 0; // need new connection messages } - cls.signon = 0; // need new connection messages } /* @@ -413,13 +420,7 @@ void Host_Connect_f (void) Con_Print("connect : connect to a multiplayer game\n"); return; } - if( sv.active ) { - SV_VM_Begin(); - CL_EstablishConnection(Cmd_Argv(1)); - SV_VM_End(); - } else { - CL_EstablishConnection(Cmd_Argv(1)); - } + CL_EstablishConnection(Cmd_Argv(1)); } @@ -735,11 +736,11 @@ void Host_Loadgame_f (void) for (i = 0;i < NUM_SPAWN_PARMS;i++) svs.clients[0].spawn_parms[i] = spawn_parms[i]; + SV_VM_End(); + // make sure we're connected to loopback if (cls.state == ca_disconnected || !(cls.state == ca_connected && cls.netcon != NULL && LHNETADDRESS_GetAddressType(&cls.netcon->peeraddress) == LHNETADDRESSTYPE_LOOP)) CL_EstablishConnection("local:1"); - - SV_VM_End(); } //============================================================================ @@ -774,6 +775,7 @@ void Host_Name_f (void) if (cmd_source == src_command) { Cvar_Set ("_cl_name", newName); + InfoString_SetValue(cls.userinfo, sizeof(cls.userinfo), "name", newName); if (cls.state == ca_connected) Cmd_ForwardToServer (); return; @@ -833,6 +835,7 @@ void Host_Playermodel_f (void) if (cmd_source == src_command) { Cvar_Set ("_cl_playermodel", newPath); + InfoString_SetValue(cls.userinfo, sizeof(cls.userinfo), "playermodel", newPath); if (cls.state == ca_connected) Cmd_ForwardToServer (); return; @@ -892,6 +895,7 @@ void Host_Playerskin_f (void) if (cmd_source == src_command) { Cvar_Set ("_cl_playerskin", newPath); + InfoString_SetValue(cls.userinfo, sizeof(cls.userinfo), "playerskin", newPath); if (cls.state == ca_connected) Cmd_ForwardToServer (); return; @@ -1109,11 +1113,16 @@ void Host_Color_f(void) if (cmd_source == src_command) { Cvar_SetValue ("_cl_color", playercolor); - if (cls.state == ca_connected) + InfoString_SetValue(cls.userinfo, sizeof(cls.userinfo), "topcolor", va("%i", top)); + InfoString_SetValue(cls.userinfo, sizeof(cls.userinfo), "bottomcolor", va("%i", bottom)); + if (cls.state == ca_connected && cls.protocol != PROTOCOL_QUAKEWORLD) Cmd_ForwardToServer (); return; } + if (cls.protocol == PROTOCOL_QUAKEWORLD) + return; + if (host_client->edict && (f = PRVM_ED_FindFunction ("SV_ChangeTeam")) && (SV_ChangeTeam = (func_t)(f - prog->functions))) { Con_DPrint("Calling SV_ChangeTeam\n"); @@ -1160,6 +1169,7 @@ void Host_Rate_f(void) if (cmd_source == src_command) { Cvar_SetValue ("_cl_rate", bound(NET_MINRATE, rate, NET_MAXRATE)); + InfoString_SetValue(cls.userinfo, sizeof(cls.userinfo), "rate", va("%i", rate)); if (cls.state == ca_connected) Cmd_ForwardToServer (); return; @@ -1280,7 +1290,6 @@ void Host_PreSpawn_f (void) MSG_WriteByte (&host_client->netconnection->message, svc_signonnum); MSG_WriteByte (&host_client->netconnection->message, 2); } - host_client->sendsignon = true; // reset the name change timer because the client will send name soon host_client->nametime = 0; @@ -1421,8 +1430,6 @@ void Host_Spawn_f (void) MSG_WriteByte (&host_client->netconnection->message, svc_signonnum); MSG_WriteByte (&host_client->netconnection->message, 3); - - host_client->sendsignon = true; } /* @@ -1965,6 +1972,305 @@ static void MaxPlayers_f(void) //============================================================================= +// QuakeWorld commands + +/* +===================== +Host_Rcon_f + + Send the rest of the command line over as + an unconnected command. +===================== +*/ +void Host_Rcon_f (void) // credit: taken from QuakeWorld +{ + int i; + lhnetaddress_t to; + lhnetsocket_t *mysocket; + + if (!rcon_password.string || !rcon_password.string[0]) + { + Con_Printf ("You must set rcon_password before issuing an rcon command.\n"); + return; + } + + for (i = 0;rcon_password.string[i];i++) + { + if (rcon_password.string[i] <= ' ') + { + Con_Printf("rcon_password is not allowed to have any whitespace.\n"); + return; + } + } + + if (cls.netcon) + to = cls.netcon->peeraddress; + else + { + if (!rcon_address.integer || !rcon_address.string[0]) + { + Con_Printf ("You must either be connected, or set the rcon_address cvar to issue rcon commands\n"); + return; + } + LHNETADDRESS_FromString(&to, rcon_address.string, sv_netport.integer); + } + mysocket = NetConn_ChooseClientSocketForAddress(&to); + if (mysocket) + { + // simply put together the rcon packet and send it + NetConn_WriteString(mysocket, va("\377\377\377\377rcon %s %s", rcon_password.string, Cmd_Args()), &to); + } +} + +/* +==================== +Host_User_f + +user + +Dump userdata / masterdata for a user +==================== +*/ +void Host_User_f (void) // credit: taken from QuakeWorld +{ + int uid; + int i; + + if (Cmd_Argc() != 2) + { + Con_Printf ("Usage: user \n"); + return; + } + + uid = atoi(Cmd_Argv(1)); + + for (i = 0;i < cl.maxclients;i++) + { + if (!cl.scores[i].name[0]) + continue; + if (cl.scores[i].qw_userid == uid || !strcasecmp(cl.scores[i].name, Cmd_Argv(1))) + { + InfoString_Print(cl.scores[i].qw_userinfo); + return; + } + } + Con_Printf ("User not in server.\n"); +} + +/* +==================== +Host_Users_f + +Dump userids for all current players +==================== +*/ +void Host_Users_f (void) // credit: taken from QuakeWorld +{ + int i; + int c; + + c = 0; + Con_Printf ("userid frags name\n"); + Con_Printf ("------ ----- ----\n"); + for (i = 0;i < cl.maxclients;i++) + { + if (cl.scores[i].name[0]) + { + Con_Printf ("%6i %4i %s\n", cl.scores[i].qw_userid, cl.scores[i].frags, cl.scores[i].name); + c++; + } + } + + Con_Printf ("%i total users\n", c); +} + +/* +================== +Host_FullServerinfo_f + +Sent by server when serverinfo changes +================== +*/ +// TODO: shouldn't this be a cvar instead? +void Host_FullServerinfo_f (void) // credit: taken from QuakeWorld +{ + char temp[512]; + if (Cmd_Argc() != 2) + { + Con_Printf ("usage: fullserverinfo \n"); + return; + } + + strlcpy (cl.qw_serverinfo, Cmd_Argv(1), sizeof(cl.qw_serverinfo)); + InfoString_GetValue(cl.qw_serverinfo, "teamplay", temp, sizeof(temp)); + cl.qw_teamplay = atoi(temp); +} + +/* +================== +Host_FullInfo_f + +Allow clients to change userinfo +================== +Casey was here :) +*/ +void Host_FullInfo_f (void) // credit: taken from QuakeWorld +{ + char key[512]; + char value[512]; + char *o; + const char *s; + + if (Cmd_Argc() != 2) + { + Con_Printf ("fullinfo \n"); + return; + } + + s = Cmd_Argv(1); + if (*s == '\\') + s++; + while (*s) + { + o = key; + while (*s && *s != '\\') + *o++ = *s++; + *o = 0; + + if (!*s) + { + Con_Printf ("MISSING VALUE\n"); + return; + } + + o = value; + s++; + while (*s && *s != '\\') + *o++ = *s++; + *o = 0; + + if (*s) + s++; + + if (!strcasecmp(key, "pmodel") || !strcasecmp(key, "emodel")) + continue; + + if (key[0] == '*') + { + Con_Printf("Can't set star-key \"%s\" to \"%s\"\n", key, value); + continue; + } + + InfoString_SetValue(cls.userinfo, sizeof(cls.userinfo), key, value); + } +} + +/* +================== +CL_SetInfo_f + +Allow clients to change userinfo +================== +*/ +void Host_SetInfo_f (void) // credit: taken from QuakeWorld +{ + if (Cmd_Argc() == 1) + { + InfoString_Print(cls.userinfo); + return; + } + if (Cmd_Argc() != 3) + { + Con_Printf ("usage: setinfo [ ]\n"); + return; + } + if (!strcasecmp(Cmd_Argv(1), "pmodel") || !strcasecmp(Cmd_Argv(1), "emodel")) + return; + if (Cmd_Argv(1)[0] == '*') + { + Con_Printf("Can't set star-key \"%s\" to \"%s\"\n", Cmd_Argv(1), Cmd_Argv(2)); + return; + } + InfoString_SetValue(cls.userinfo, sizeof(cls.userinfo), Cmd_Argv(1), Cmd_Argv(2)); + if (cls.state == ca_connected) + Cmd_ForwardToServer (); +} + +/* +==================== +Host_Packet_f + +packet + +Contents allows \n escape character +==================== +*/ +void Host_Packet_f (void) // credit: taken from QuakeWorld +{ + char send[2048]; + int i, l; + const char *in; + char *out; + lhnetaddress_t address; + lhnetsocket_t *mysocket; + + if (Cmd_Argc() != 3) + { + Con_Printf ("packet \n"); + return; + } + + if (!LHNETADDRESS_FromString (&address, Cmd_Argv(1), sv_netport.integer)) + { + Con_Printf ("Bad address\n"); + return; + } + + in = Cmd_Argv(2); + out = send+4; + send[0] = send[1] = send[2] = send[3] = 0xff; + + l = (int)strlen (in); + for (i=0 ; i= send + sizeof(send) - 1) + break; + if (in[i] == '\\' && in[i+1] == 'n') + { + *out++ = '\n'; + i++; + } + else if (in[i] == '\\' && in[i+1] == '0') + { + *out++ = '\0'; + i++; + } + else if (in[i] == '\\' && in[i+1] == 't') + { + *out++ = '\t'; + i++; + } + else if (in[i] == '\\' && in[i+1] == 'r') + { + *out++ = '\r'; + i++; + } + else if (in[i] == '\\' && in[i+1] == '"') + { + *out++ = '\"'; + i++; + } + else + *out++ = in[i]; + } + + mysocket = NetConn_ChooseClientSocketForAddress(&address); + if (mysocket) + NetConn_Write(mysocket, send, out - send, &address); +} + +//============================================================================= + /* ================== Host_InitCommands @@ -1972,6 +2278,8 @@ Host_InitCommands */ void Host_InitCommands (void) { + strcpy(cls.userinfo, "\\name\\player\\team\\none\\topcolor\\0\\bottomcolor\\0\\rate\\10000\\msg\\1\\*ver\\dp"); + Cmd_AddCommand ("status", Host_Status_f, "print server status information"); Cmd_AddCommand ("quit", Host_Quit_f, "quit the game"); if (gamemode == GAME_NEHAHRA) @@ -2040,6 +2348,16 @@ void Host_InitCommands (void) Cmd_AddCommand ("sendcvar", Host_SendCvar_f, "sends the value of a cvar to the server as a sentcvar command, for use by QuakeC"); // By [515] + Cvar_RegisterVariable (&rcon_password); + Cvar_RegisterVariable (&rcon_address); + Cmd_AddCommand ("rcon", Host_Rcon_f, "sends a command to the server console (if your rcon_password matches the server's rcon_password), or to the address specified by rcon_address when not connected (again rcon_password must match the server's)"); + Cmd_AddCommand ("user", Host_User_f, "prints additional information about a player number or name on the scoreboard"); + Cmd_AddCommand ("users", Host_Users_f, "prints additional information about all players on the scoreboard"); + Cmd_AddCommand ("fullserverinfo", Host_FullServerinfo_f, "internal use only, sent by server to client to update client's local copy of serverinfo string"); + Cmd_AddCommand ("fullinfo", Host_FullInfo_f, "allows client to modify their userinfo"); + Cmd_AddCommand ("setinfo", Host_SetInfo_f, "modifies your userinfo"); + Cmd_AddCommand ("packet", Host_Packet_f, "send a packet to the specified address:port containing a text string"); + Cvar_RegisterVariable(&sv_cheats); }