// cl_main.c -- client main loop #include <u.h>#include <libc.h>#include <stdio.h>#include "dat.h"#include "fns.h" cvar_t *adr0;cvar_t *adr1;cvar_t *adr2;cvar_t *adr3;cvar_t *adr4;cvar_t *adr5;cvar_t *adr6;cvar_t *adr7;cvar_t *adr8; cvar_t *cl_stereo_separation;cvar_t *cl_stereo; cvar_t *rcon_client_password;cvar_t *rcon_address; cvar_t *cl_noskins;cvar_t *cl_autoskins;cvar_t *cl_footsteps;cvar_t *cl_timeout;cvar_t *cl_predict;//cvar_t *cl_minfps;cvar_t *cl_maxfps;cvar_t *cl_gun; cvar_t *cl_add_particles;cvar_t *cl_add_lights;cvar_t *cl_add_entities;cvar_t *cl_add_blend; cvar_t *cl_shownet;cvar_t *cl_showmiss;cvar_t *cl_showclamp; cvar_t *cl_paused;cvar_t *cl_timedemo; cvar_t *cl_lightlevel; //// userinfo//cvar_t *info_password;cvar_t *info_spectator;cvar_t *name;cvar_t *skin;cvar_t *rate;cvar_t *fov;cvar_t *msg;cvar_t *hand;cvar_t *gender;cvar_t *gender_auto; cvar_t *cl_vwep; client_static_t cls;client_state_t cl; centity_t cl_entities[MAX_EDICTS]; entity_state_t cl_parse_entities[MAX_PARSE_ENTITIES]; extern cvar_t *allow_download;extern cvar_t *allow_download_players;extern cvar_t *allow_download_models;extern cvar_t *allow_download_sounds;extern cvar_t *allow_download_maps; //====================================================================== voidCL_SetGameInput(k){ switch(cls.key_dest = k){ case key_game: IN_Grabm(1); if(Cvar_VariableValue("maxclients") == 1 && Com_ServerState()) Cvar_Set("paused", "0"); break; default: IN_Grabm(0); if(Cvar_VariableValue("maxclients") == 1 && Com_ServerState()) Cvar_Set("paused", "1"); break; }} /*====================CL_WriteDemoMessage Dumps the current net message, prefixed by the length====================*/void CL_WriteDemoMessage (void){ int len, swlen; // the first eight bytes are just packet sequencing stuff len = net_message.cursize-8; swlen = LittleLong(len); fwrite (&swlen, 4, 1, cls.demofile); fwrite (net_message.data+8, len, 1, cls.demofile);} /*====================CL_Stop_f stop recording a demo====================*/void CL_Stop_f (void){ int len; if (!cls.demorecording) { Com_Printf ("Not recording a demo.\n"); return; } // finish up len = -1; fwrite (&len, 4, 1, cls.demofile); fclose (cls.demofile); cls.demofile = NULL; cls.demorecording = false; Com_Printf ("Stopped demo.\n");} /*====================CL_Record_f record <demoname> Begins recording a demo from the current position====================*/void CL_Record_f (void){ char name[MAX_OSPATH]; char buf_data[MAX_MSGLEN]; sizebuf_t buf; int i; int len; entity_state_t *ent; entity_state_t nullstate; if (Cmd_Argc() != 2) { Com_Printf ("record <demoname>\n"); return; } if (cls.demorecording) { Com_Printf ("Already recording.\n"); return; } if (cls.state != ca_active) { Com_Printf ("You must be in a level to record.\n"); return; } // // open the demo file // Com_sprintf (name, sizeof(name), "%s/demos/%s.dm2", FS_Gamedir(), Cmd_Argv(1)); Com_Printf ("recording to %s.\n", name); FS_CreatePath (name); cls.demofile = fopen (name, "wb"); if (!cls.demofile) { Com_Printf ("ERROR: couldn't open.\n"); return; } cls.demorecording = true; // don't start saving messages until a non-delta compressed message is received cls.demowaiting = true; // // write out messages to hold the startup information // SZ_Init (&buf, (uchar *)buf_data, sizeof(buf_data)); // send the serverdata MSG_WriteByte (&buf, svc_serverdata); MSG_WriteLong (&buf, PROTOCOL_VERSION); MSG_WriteLong (&buf, 0x10000 + cl.servercount); MSG_WriteByte (&buf, 1); // demos are always attract loops MSG_WriteString (&buf, cl.gamedir); MSG_WriteShort (&buf, cl.playernum); MSG_WriteString (&buf, cl.configstrings[CS_NAME]); // configstrings for (i=0 ; i<MAX_CONFIGSTRINGS ; i++) { if (cl.configstrings[i][0]) { if (buf.cursize + strlen (cl.configstrings[i]) + 32 > buf.maxsize) { // write it out len = LittleLong (buf.cursize); fwrite (&len, 4, 1, cls.demofile); fwrite (buf.data, buf.cursize, 1, cls.demofile); buf.cursize = 0; } MSG_WriteByte (&buf, svc_configstring); MSG_WriteShort (&buf, i); MSG_WriteString (&buf, cl.configstrings[i]); } } // baselines memset (&nullstate, 0, sizeof(nullstate)); for (i=0; i<MAX_EDICTS ; i++) { ent = &cl_entities[i].baseline; if (!ent->modelindex) continue; if (buf.cursize + 64 > buf.maxsize) { // write it out len = LittleLong (buf.cursize); fwrite (&len, 4, 1, cls.demofile); fwrite (buf.data, buf.cursize, 1, cls.demofile); buf.cursize = 0; } MSG_WriteByte (&buf, svc_spawnbaseline); MSG_WriteDeltaEntity (&nullstate, &cl_entities[i].baseline, &buf, true, true); } MSG_WriteByte (&buf, svc_stufftext); MSG_WriteString (&buf, "precache\n"); // write it to the demo file len = LittleLong (buf.cursize); fwrite (&len, 4, 1, cls.demofile); fwrite (buf.data, buf.cursize, 1, cls.demofile); // the rest of the demo file will be individual frames} /* adds the current command line as a clc_stringcmd to the client message. * things like godmode, noclip, etc, are commands directed to the server, so * when they are typed in at the console, they will need to be forwarded. */void Cmd_ForwardToServer (void){ char *cmd; cmd = Cmd_Argv(0); if(cls.state <= ca_connected || *cmd == '-' || *cmd == '+'){ Com_Printf("Unknown command \"%s\"\n", cmd); return; } MSG_WriteByte(&cls.netchan.message, clc_stringcmd); SZ_Print(&cls.netchan.message, cmd); if(Cmd_Argc() > 1){ SZ_Print(&cls.netchan.message, " "); SZ_Print(&cls.netchan.message, Cmd_Args()); }} voidCL_Setenv_f(void){ int i, l = 0, argc; char name[1024], val[1024], *env; argc = Cmd_Argc(); if(argc > 2){ strncpy(name, Cmd_Argv(1), sizeof name); for(i = 2; i < argc; i++){ strncpy(val+l, Cmd_Argv(i), sizeof(name) - l - 2); val[sizeof(val)-2] = 0; strcat(val, " "); l = strlen(val); } putenv(name, val); }else if(argc == 2){ env = getenv(Cmd_Argv(1)); if(env){ Com_Printf("%s=%s\n", Cmd_Argv(1), env); free(env); }else Com_Printf("%s undefined\n", Cmd_Argv(1), env); }} voidCL_ForwardToServer_f(void){ if(cls.state != ca_connected && cls.state != ca_active){ Com_Printf("Can't \"%s\", not connected\n", Cmd_Argv(0)); return; } /* don't forward the first argument */ if(Cmd_Argc() > 1){ MSG_WriteByte(&cls.netchan.message, clc_stringcmd); SZ_Print(&cls.netchan.message, Cmd_Args()); }} /*==================CL_Pause_f==================*/void CL_Pause_f (void){ // never pause in multiplayer if (Cvar_VariableValue ("maxclients") > 1 || !Com_ServerState ()) { Cvar_SetValue ("paused", 0); return; } Cvar_SetValue ("paused", !cl_paused->value);} /*==================CL_Quit_f==================*/void CL_Quit_f (void){ CL_Disconnect (); Com_Quit ();} /*================CL_Drop Called after an ERR_DROP was thrown================*/void CL_Drop (void){ if (cls.state == ca_uninitialized) return; if (cls.state == ca_disconnected) return; CL_Disconnect (); // drop loading plaque unless this is the initial game start if (cls.disable_servercount != -1) SCR_EndLoadingPlaque (); // get rid of loading plaque} /*=======================CL_SendConnectPacket We have gotten a challenge from the server, so try andconnect.======================*/void CL_SendConnectPacket (void){ netadr_t adr; int port; if (!NET_StringToAdr (cls.servername, &adr)) { Com_Printf ("Bad server address\n"); cls.connect_time = 0; return; } if (adr.port == 0) adr.port = BigShort (PORT_SERVER); port = Cvar_VariableValue ("qport"); userinfo_modified = false; Netchan_OutOfBandPrint (NS_CLIENT, adr, "connect %i %i %i \"%s\"\n", PROTOCOL_VERSION, port, cls.challenge, Cvar_Userinfo() );} /*=================CL_CheckForResend Resend a connect message if the last one has timed out=================*/void CL_CheckForResend (void){ netadr_t adr; // if the local server is running and we aren't // then connect if (cls.state == ca_disconnected && Com_ServerState() ) { cls.state = ca_connecting; strncpy (cls.servername, "localhost", sizeof(cls.servername)-1); // we don't need a challenge on the localhost CL_SendConnectPacket (); return;// cls.connect_time = -99999; // CL_CheckForResend() will fire immediately } // resend if we haven't gotten a reply yet if (cls.state != ca_connecting) return; if (cls.realtime - cls.connect_time < 3000) return; if (!NET_StringToAdr (cls.servername, &adr)) { Com_Printf ("Bad server address\n"); cls.state = ca_disconnected; return; } if (adr.port == 0) adr.port = BigShort (PORT_SERVER); cls.connect_time = cls.realtime; // for retransmit requests Com_Printf ("Connecting to %s...\n", cls.servername); Netchan_OutOfBandPrint (NS_CLIENT, adr, "getchallenge\n");} /*================CL_Connect_f ================*/void CL_Connect_f (void){ char *server; if (Cmd_Argc() != 2) { Com_Printf ("usage: connect <server>\n"); return; } if (Com_ServerState ()) { // if running a local server, kill it and reissue SV_Shutdown (va("Server quit\n", msg), false); } else { CL_Disconnect (); } server = Cmd_Argv (1); NET_Config (true); // allow remote CL_Disconnect (); cls.state = ca_connecting; strncpy (cls.servername, server, sizeof(cls.servername)-1); cls.connect_time = -99999; // CL_CheckForResend() will fire immediately} /*=====================CL_Rcon_f Send the rest of the command line over as an unconnected command.=====================*/void CL_Rcon_f (void){ char message[1024];Lines 1–500 of 1774. Load more
// cl_main.c -- client main loop #include <u.h> #include <libc.h> #include <stdio.h> #include "dat.h" #include "fns.h" cvar_t *adr0; cvar_t *adr1; cvar_t *adr2; cvar_t *adr3; cvar_t *adr4; cvar_t *adr5; cvar_t *adr6; cvar_t *adr7; cvar_t *adr8; cvar_t *cl_stereo_separation; cvar_t *cl_stereo; cvar_t *rcon_client_password; cvar_t *rcon_address; cvar_t *cl_noskins; cvar_t *cl_autoskins; cvar_t *cl_footsteps; cvar_t *cl_timeout; cvar_t *cl_predict; //cvar_t *cl_minfps; cvar_t *cl_maxfps; cvar_t *cl_gun; cvar_t *cl_add_particles; cvar_t *cl_add_lights; cvar_t *cl_add_entities; cvar_t *cl_add_blend; cvar_t *cl_shownet; cvar_t *cl_showmiss; cvar_t *cl_showclamp; cvar_t *cl_paused; cvar_t *cl_timedemo; cvar_t *cl_lightlevel; // // userinfo // cvar_t *info_password; cvar_t *info_spectator; cvar_t *name; cvar_t *skin; cvar_t *rate; cvar_t *fov; cvar_t *msg; cvar_t *hand; cvar_t *gender; cvar_t *gender_auto; cvar_t *cl_vwep; client_static_t cls; client_state_t cl; centity_t cl_entities[MAX_EDICTS]; entity_state_t cl_parse_entities[MAX_PARSE_ENTITIES]; extern cvar_t *allow_download; extern cvar_t *allow_download_players; extern cvar_t *allow_download_models; extern cvar_t *allow_download_sounds; extern cvar_t *allow_download_maps; //====================================================================== void CL_SetGameInput(k) { switch(cls.key_dest = k){ case key_game: IN_Grabm(1); if(Cvar_VariableValue("maxclients") == 1 && Com_ServerState()) Cvar_Set("paused", "0"); break; default: IN_Grabm(0); if(Cvar_VariableValue("maxclients") == 1 && Com_ServerState()) Cvar_Set("paused", "1"); break; } } /* ==================== CL_WriteDemoMessage Dumps the current net message, prefixed by the length ==================== */ void CL_WriteDemoMessage (void) { int len, swlen; // the first eight bytes are just packet sequencing stuff len = net_message.cursize-8; swlen = LittleLong(len); fwrite (&swlen, 4, 1, cls.demofile); fwrite (net_message.data+8, len, 1, cls.demofile); } /* ==================== CL_Stop_f stop recording a demo ==================== */ void CL_Stop_f (void) { int len; if (!cls.demorecording) { Com_Printf ("Not recording a demo.\n"); return; } // finish up len = -1; fwrite (&len, 4, 1, cls.demofile); fclose (cls.demofile); cls.demofile = NULL; cls.demorecording = false; Com_Printf ("Stopped demo.\n"); } /* ==================== CL_Record_f record <demoname> Begins recording a demo from the current position ==================== */ void CL_Record_f (void) { char name[MAX_OSPATH]; char buf_data[MAX_MSGLEN]; sizebuf_t buf; int i; int len; entity_state_t *ent; entity_state_t nullstate; if (Cmd_Argc() != 2) { Com_Printf ("record <demoname>\n"); return; } if (cls.demorecording) { Com_Printf ("Already recording.\n"); return; } if (cls.state != ca_active) { Com_Printf ("You must be in a level to record.\n"); return; } // // open the demo file // Com_sprintf (name, sizeof(name), "%s/demos/%s.dm2", FS_Gamedir(), Cmd_Argv(1)); Com_Printf ("recording to %s.\n", name); FS_CreatePath (name); cls.demofile = fopen (name, "wb"); if (!cls.demofile) { Com_Printf ("ERROR: couldn't open.\n"); return; } cls.demorecording = true; // don't start saving messages until a non-delta compressed message is received cls.demowaiting = true; // // write out messages to hold the startup information // SZ_Init (&buf, (uchar *)buf_data, sizeof(buf_data)); // send the serverdata MSG_WriteByte (&buf, svc_serverdata); MSG_WriteLong (&buf, PROTOCOL_VERSION); MSG_WriteLong (&buf, 0x10000 + cl.servercount); MSG_WriteByte (&buf, 1); // demos are always attract loops MSG_WriteString (&buf, cl.gamedir); MSG_WriteShort (&buf, cl.playernum); MSG_WriteString (&buf, cl.configstrings[CS_NAME]); // configstrings for (i=0 ; i<MAX_CONFIGSTRINGS ; i++) { if (cl.configstrings[i][0]) { if (buf.cursize + strlen (cl.configstrings[i]) + 32 > buf.maxsize) { // write it out len = LittleLong (buf.cursize); fwrite (&len, 4, 1, cls.demofile); fwrite (buf.data, buf.cursize, 1, cls.demofile); buf.cursize = 0; } MSG_WriteByte (&buf, svc_configstring); MSG_WriteShort (&buf, i); MSG_WriteString (&buf, cl.configstrings[i]); } } // baselines memset (&nullstate, 0, sizeof(nullstate)); for (i=0; i<MAX_EDICTS ; i++) { ent = &cl_entities[i].baseline; if (!ent->modelindex) continue; if (buf.cursize + 64 > buf.maxsize) { // write it out len = LittleLong (buf.cursize); fwrite (&len, 4, 1, cls.demofile); fwrite (buf.data, buf.cursize, 1, cls.demofile); buf.cursize = 0; } MSG_WriteByte (&buf, svc_spawnbaseline); MSG_WriteDeltaEntity (&nullstate, &cl_entities[i].baseline, &buf, true, true); } MSG_WriteByte (&buf, svc_stufftext); MSG_WriteString (&buf, "precache\n"); // write it to the demo file len = LittleLong (buf.cursize); fwrite (&len, 4, 1, cls.demofile); fwrite (buf.data, buf.cursize, 1, cls.demofile); // the rest of the demo file will be individual frames } /* adds the current command line as a clc_stringcmd to the client message. * things like godmode, noclip, etc, are commands directed to the server, so * when they are typed in at the console, they will need to be forwarded. */ void Cmd_ForwardToServer (void) { char *cmd; cmd = Cmd_Argv(0); if(cls.state <= ca_connected || *cmd == '-' || *cmd == '+'){ Com_Printf("Unknown command \"%s\"\n", cmd); return; } MSG_WriteByte(&cls.netchan.message, clc_stringcmd); SZ_Print(&cls.netchan.message, cmd); if(Cmd_Argc() > 1){ SZ_Print(&cls.netchan.message, " "); SZ_Print(&cls.netchan.message, Cmd_Args()); } } void CL_Setenv_f(void) { int i, l = 0, argc; char name[1024], val[1024], *env; argc = Cmd_Argc(); if(argc > 2){ strncpy(name, Cmd_Argv(1), sizeof name); for(i = 2; i < argc; i++){ strncpy(val+l, Cmd_Argv(i), sizeof(name) - l - 2); val[sizeof(val)-2] = 0; strcat(val, " "); l = strlen(val); } putenv(name, val); }else if(argc == 2){ env = getenv(Cmd_Argv(1)); if(env){ Com_Printf("%s=%s\n", Cmd_Argv(1), env); free(env); }else Com_Printf("%s undefined\n", Cmd_Argv(1), env); } } void CL_ForwardToServer_f(void) { if(cls.state != ca_connected && cls.state != ca_active){ Com_Printf("Can't \"%s\", not connected\n", Cmd_Argv(0)); return; } /* don't forward the first argument */ if(Cmd_Argc() > 1){ MSG_WriteByte(&cls.netchan.message, clc_stringcmd); SZ_Print(&cls.netchan.message, Cmd_Args()); } } /* ================== CL_Pause_f ================== */ void CL_Pause_f (void) { // never pause in multiplayer if (Cvar_VariableValue ("maxclients") > 1 || !Com_ServerState ()) { Cvar_SetValue ("paused", 0); return; } Cvar_SetValue ("paused", !cl_paused->value); } /* ================== CL_Quit_f ================== */ void CL_Quit_f (void) { CL_Disconnect (); Com_Quit (); } /* ================ CL_Drop Called after an ERR_DROP was thrown ================ */ void CL_Drop (void) { if (cls.state == ca_uninitialized) return; if (cls.state == ca_disconnected) return; CL_Disconnect (); // drop loading plaque unless this is the initial game start if (cls.disable_servercount != -1) SCR_EndLoadingPlaque (); // get rid of loading plaque } /* ======================= CL_SendConnectPacket We have gotten a challenge from the server, so try and connect. ====================== */ void CL_SendConnectPacket (void) { netadr_t adr; int port; if (!NET_StringToAdr (cls.servername, &adr)) { Com_Printf ("Bad server address\n"); cls.connect_time = 0; return; } if (adr.port == 0) adr.port = BigShort (PORT_SERVER); port = Cvar_VariableValue ("qport"); userinfo_modified = false; Netchan_OutOfBandPrint (NS_CLIENT, adr, "connect %i %i %i \"%s\"\n", PROTOCOL_VERSION, port, cls.challenge, Cvar_Userinfo() ); } /* ================= CL_CheckForResend Resend a connect message if the last one has timed out ================= */ void CL_CheckForResend (void) { netadr_t adr; // if the local server is running and we aren't // then connect if (cls.state == ca_disconnected && Com_ServerState() ) { cls.state = ca_connecting; strncpy (cls.servername, "localhost", sizeof(cls.servername)-1); // we don't need a challenge on the localhost CL_SendConnectPacket (); return; // cls.connect_time = -99999; // CL_CheckForResend() will fire immediately } // resend if we haven't gotten a reply yet if (cls.state != ca_connecting) return; if (cls.realtime - cls.connect_time < 3000) return; if (!NET_StringToAdr (cls.servername, &adr)) { Com_Printf ("Bad server address\n"); cls.state = ca_disconnected; return; } if (adr.port == 0) adr.port = BigShort (PORT_SERVER); cls.connect_time = cls.realtime; // for retransmit requests Com_Printf ("Connecting to %s...\n", cls.servername); Netchan_OutOfBandPrint (NS_CLIENT, adr, "getchallenge\n"); } /* ================ CL_Connect_f ================ */ void CL_Connect_f (void) { char *server; if (Cmd_Argc() != 2) { Com_Printf ("usage: connect <server>\n"); return; } if (Com_ServerState ()) { // if running a local server, kill it and reissue SV_Shutdown (va("Server quit\n", msg), false); } else { CL_Disconnect (); } server = Cmd_Argv (1); NET_Config (true); // allow remote CL_Disconnect (); cls.state = ca_connecting; strncpy (cls.servername, server, sizeof(cls.servername)-1); cls.connect_time = -99999; // CL_CheckForResend() will fire immediately } /* ===================== CL_Rcon_f Send the rest of the command line over as an unconnected command. ===================== */ void CL_Rcon_f (void) { char message[1024];