//Sets the gamedir and path to a different directory. void SV_Gamedir_f (void) { char *dir; if (Cmd_Argc() == 1) { Com_Printf ("Current gamedir: %s\n", com_gamedirfile); return; } if (Cmd_Argc() != 2) { Com_Printf ("Usage: gamedir <newdir>\n"); return; } dir = Cmd_Argv(1); if (strstr(dir, "..") || strstr(dir, "/") || strstr(dir, "\\") || strstr(dir, ":")) { Com_Printf ("gamedir should be a single filename, not a path\n"); return; } #ifndef SERVERONLY if (CL_ClientState()) { Com_Printf ("you must disconnect before changing gamedir\n"); return; } #endif FS_SetGamedir (dir); Info_SetValueForStarKey (svs.info, "*gamedir", dir, MAX_SERVERINFO_STRING); }
qbool VM_LoadNative( vm_t * vm ) { char name[MAX_OSPATH]; char *gpath = NULL; void ( *dllEntry ) ( void * ); while ( ( gpath = FS_NextPath( gpath ) ) ) { snprintf(name, sizeof(name), "%s/%s." DLEXT, gpath, vm->name); vm->hInst = Sys_DLOpen( name ); if ( vm->hInst ) { Con_DPrintf( "LoadLibrary (%s)\n", name ); break; } } if ( !vm->hInst ) return false; dllEntry = (void (EXPORT_FN *)(void *)) Sys_DLProc( (DL_t) vm->hInst, "dllEntry" ); vm->vmMain = (intptr_t (EXPORT_FN *)(int,int,int,int,int,int,int,int,int,int,int,int,int)) Sys_DLProc( (DL_t) vm->hInst, "vmMain" ); if ( !dllEntry || !vm->vmMain ) { VM_Unload( vm ); SV_Error( "VM_LoadNative: couldn't initialize module %s", name ); } dllEntry( (void *) vm->syscall ); Info_SetValueForStarKey( svs.info, "*progs", DLEXT, MAX_SERVERINFO_STRING ); vm->type = VM_NATIVE; return true; }
/* SV_Gamedir Sets the fake *gamedir to a different directory. */ static void SV_Gamedir (void) { const char *dir; if (Cmd_Argc () == 1) { SV_Printf ("Current *gamedir: %s\n", Info_ValueForKey (svs.info, "*gamedir")); return; } if (Cmd_Argc () != 2) { SV_Printf ("Usage: sv_gamedir <newgamedir>\n"); return; } dir = Cmd_Argv (1); if (strstr (dir, "..") || strstr (dir, "/") || strstr (dir, "\\") || strstr (dir, ":")) { SV_Printf ("*Gamedir should be a single filename, not a path\n"); return; } Info_SetValueForStarKey (svs.info, "*gamedir", dir, !sv_highchars->int_val); }
void SV_Gamedir_f (void) { char *dir; if (Cmd_Argc() == 1) { Con_Printf ("Current gamedir: %s\n", com_gamedir); return; } if (Cmd_Argc() != 2) { Con_Printf ("Usage: gamedir <newdir>\n"); return; } dir = Cmd_Argv(1); if (strstr(dir, "..") || strstr(dir, "/") || strstr(dir, "\\") || strstr(dir, ":") ) { Con_Printf ("Gamedir should be a single filename, not a path\n"); return; } COM_Gamedir (dir); Info_SetValueForStarKey (svs.info, "*gamedir", dir, MAX_SERVERINFO_STRING); }
void SV_InitOperatorCommands (void) { if (COM_CheckParm ("-cheats")) { sv_allow_cheats = true; Info_SetValueForStarKey (svs.info, "*cheats", "ON", MAX_SERVERINFO_STRING); } Cmd_AddCommand ("logfile", SV_Logfile_f); Cmd_AddCommand ("fraglogfile", SV_Fraglogfile_f); Cmd_AddCommand ("snap", SV_Snap_f); Cmd_AddCommand ("snapall", SV_SnapAll_f); Cmd_AddCommand ("kick", SV_Kick_f); Cmd_AddCommand ("status", SV_Status_f); Cmd_AddCommand ("map", SV_Map_f); Cmd_AddCommand ("setmaster", SV_SetMaster_f); Cmd_AddCommand ("say", SV_ConSay_f); Cmd_AddCommand ("heartbeat", SV_Heartbeat_f); Cmd_AddCommand ("quit", SV_Quit_f); Cmd_AddCommand ("god", SV_God_f); Cmd_AddCommand ("give", SV_Give_f); Cmd_AddCommand ("noclip", SV_Noclip_f); Cmd_AddCommand ("serverinfo", SV_Serverinfo_f); Cmd_AddCommand ("localinfo", SV_Localinfo_f); Cmd_AddCommand ("user", SV_User_f); Cmd_AddCommand ("gamedir", SV_Gamedir_f); Cmd_AddCommand ("sv_gamedir", SV_Gamedir); Cmd_AddCommand ("floodprot", SV_Floodprot_f); Cmd_AddCommand ("floodprotmsg", SV_Floodprotmsg_f); cl_warncmd.value = 1; }
void Info_SetValueForKey (char *s, const char *key, const char *value, int maxsize) { if (key[0] == '*') { return; } Info_SetValueForStarKey (s, key, value, maxsize); }
/* <4113e> ../engine/info.c:361 */ void Info_SetValueForKey(char *s, const char *key, const char *value, int maxsize) { if (key[0] == '*') { Con_Printf("Can't set * keys\n"); return; } Info_SetValueForStarKey(s, key, value, maxsize); }
//Cvar system calls this when a CVAR_SERVERINFO cvar changes void SV_ServerinfoChanged (char *key, char *string) { char value[MAX_INFO_KEY] = ""; // force serverinfo "0" vars to be "". if (!strcmp(string, "0")) string = ""; if (strcmp(string, Info_ValueForKey (g_cluster.info, key, value, sizeof(value)))) { Info_SetValueForStarKey (g_cluster.info, key, string, MAX_SERVERINFO_STRING); } }
void SV_InitOperatorCommands (void) { Cvar_SetCurrentGroup(CVAR_GROUP_SERVER_MAIN); Cvar_Register (&sv_floodprotmsg); Cvar_Register (&sv_cheats); Cvar_ResetCurrentGroup(); if (COM_CheckParm ("-cheats")) { sv_allow_cheats = true; Cvar_SetValue (&sv_cheats, 1); Info_SetValueForStarKey (svs.info, "*cheats", "ON", MAX_SERVERINFO_STRING); } Cmd_AddCommand ("fraglogfile", SV_Fraglogfile_f); Cmd_AddCommand ("snap", SV_Snap_f); Cmd_AddCommand ("snapall", SV_SnapAll_f); Cmd_AddCommand ("kick", SV_Kick_f); Cmd_AddCommand ("status", SV_Status_f); Cmd_AddCommand ("serverstatus", SV_Status_f); Cmd_AddCommand ("map", SV_Map_f); Cmd_AddCommand ("devmap", SV_Map_f); Cmd_AddCommand ("setmaster", SV_SetMaster_f); Cmd_AddCommand ("heartbeat", SV_Heartbeat_f); if (dedicated) { Cmd_AddCommand ("say", SV_ConSay_f); Cmd_AddCommand ("quit", SV_Quit_f); Cmd_AddCommand ("user", SV_User_f); Cmd_AddCommand ("serverinfo", SV_Serverinfo_f); } #ifndef SERVERONLY if (!dedicated) { Cmd_AddCommand ("save", SV_SaveGame_f); Cmd_AddCommand ("load", SV_LoadGame_f); } #endif Cmd_AddCommand ("localinfo", SV_Localinfo_f); Cmd_AddCommand ("gamedir", SV_Gamedir_f); Cmd_AddCommand ("sv_gamedir", SV_Gamedir); cl_warncmd.value = 1; }
/* ======================= CL_SendConnectPacket called by CL_Connect_f and CL_CheckResend ====================== */ void CL_SendConnectPacket (void) { netadr_t adr; char data[2048]; double t1, t2; // JACK: Fixed bug where DNS lookups would cause two connects real fast // Now, adds lookup time to the connect time. // Should I add it to realtime instead?!?! if (cls.state != ca_disconnected) return; t1 = Sys_DoubleTime (); if (!NET_StringToAdr (cls.servername, &adr)) { Con_Printf ("Bad server address\n"); connect_time = -1; return; } if (!NET_IsClientLegal(&adr)) { Con_Printf ("Illegal server address\n"); connect_time = -1; return; } if (adr.port == 0) adr.port = BigShort (27500); t2 = Sys_DoubleTime (); connect_time = realtime+t2-t1; // for retransmit requests cls.qport = Cvar_VariableValue("qport"); Info_SetValueForStarKey (cls.userinfo, "*ip", NET_AdrToString(adr), MAX_INFO_STRING); //Con_Printf ("Connecting to %s...\n", cls.servername); sprintf (data, "%c%c%c%cconnect %i %i %i \"%s\"\n", 255, 255, 255, 255, PROTOCOL_VERSION, cls.qport, cls.challenge, cls.userinfo); NET_SendPacket (strlen(data), data, adr); }
/* ======================= CL_SendConnectPacket called by CL_Connect_f and CL_CheckResend ====================== */ void CL_SendConnectPacket (void) { char data[2048]; char biguserinfo[MAX_INFO_STRING + 32]; if (cls.state != ca_disconnected) return; connect_time = cls.realtime; // for retransmit requests cls.qport = Cvar_Value("qport"); // let the server know what extensions we support strcpy (biguserinfo, cls.userinfo); Info_SetValueForStarKey (biguserinfo, "*z_ext", va("%i", CLIENT_EXTENSIONS), sizeof(biguserinfo)); sprintf (data, "\xff\xff\xff\xff" "connect %i %i %i \"%s\"\n", PROTOCOL_VERSION, cls.qport, cls.challenge, biguserinfo); NET_SendPacket (NS_CLIENT, strlen(data), data, cls.server_adr); }
void PR_LoadProgs (void) { int i; char num[32]; char name[MAX_OSPATH]; int filesize; // flush the non-C variable lookup cache for (i = 0; i < GEFV_CACHESIZE; i++) gefvCache[i].field[0] = 0; // clear pr_newstrtbl PF_clear_strtbl(); snprintf(name, sizeof(name), "%s.dat", sv_progsname.string); progs = (dprograms_t *)FS_LoadHunkFile (name, &filesize); if (!progs) progs = (dprograms_t *)FS_LoadHunkFile ("qwprogs.dat", &filesize); if (!progs) progs = (dprograms_t *)FS_LoadHunkFile ("spprogs.dat", &filesize); #ifdef WITH_NQPROGS pr_nqprogs = false; if (!progs || Cvar_Value("sv_forcenqprogs")) { progs = (dprograms_t *)FS_LoadHunkFile ("progs.dat", &filesize); if (progs) pr_nqprogs = true; } #endif if (!progs) SV_Error ("PR_LoadProgs: couldn't load progs.dat"); Con_DPrintf ("Programs occupy %iK.\n", filesize/1024); // add prog crc to the serverinfo snprintf (num, sizeof(num), "%i", CRC_Block ((byte *)progs, filesize)); #ifdef USE_PR2 Info_SetStar( &_localinfo_, "*qvm", "DAT" ); // Info_SetValueForStarKey (svs.info, "*qvm", "DAT", MAX_SERVERINFO_STRING); #endif Info_SetValueForStarKey (svs.info, "*progs", num, MAX_SERVERINFO_STRING); // byte swap the header for (i = 0; i < (int) sizeof(*progs) / 4 ; i++) ((int *)progs)[i] = LittleLong ( ((int *)progs)[i] ); if (progs->version != PROG_VERSION) SV_Error ("qwprogs.dat has wrong version number (%i should be %i)", progs->version, PROG_VERSION); if (progs->crc != (pr_nqprogs ? NQ_PROGHEADER_CRC : PROGHEADER_CRC)) SV_Error ("You must have the qwprogs.dat from QuakeWorld installed"); pr_functions = (dfunction_t *)((byte *)progs + progs->ofs_functions); pr_strings = (char *)progs + progs->ofs_strings; pr_globaldefs = (ddef_t *)((byte *)progs + progs->ofs_globaldefs); pr_fielddefs = (ddef_t *)((byte *)progs + progs->ofs_fielddefs); pr_statements = (dstatement_t *)((byte *)progs + progs->ofs_statements); num_prstr = 0; pr_global_struct = (globalvars_t *)((byte *)progs + progs->ofs_globals); pr_globals = (float *)pr_global_struct; pr_edict_size = progs->entityfields * 4 + sizeof (edict_t) - sizeof(entvars_t); // byte swap the lumps for (i = 0; i < progs->numstatements; i++) { pr_statements[i].op = LittleShort(pr_statements[i].op); pr_statements[i].a = LittleShort(pr_statements[i].a); pr_statements[i].b = LittleShort(pr_statements[i].b); pr_statements[i].c = LittleShort(pr_statements[i].c); } for (i = 0; i < progs->numfunctions; i++) { pr_functions[i].first_statement = LittleLong (pr_functions[i].first_statement); pr_functions[i].parm_start = LittleLong (pr_functions[i].parm_start); pr_functions[i].s_name = LittleLong (pr_functions[i].s_name); pr_functions[i].s_file = LittleLong (pr_functions[i].s_file); pr_functions[i].numparms = LittleLong (pr_functions[i].numparms); pr_functions[i].locals = LittleLong (pr_functions[i].locals); } for (i = 0; i < progs->numglobaldefs; i++) { pr_globaldefs[i].type = LittleShort (pr_globaldefs[i].type); pr_globaldefs[i].ofs = LittleShort (pr_globaldefs[i].ofs); pr_globaldefs[i].s_name = LittleLong (pr_globaldefs[i].s_name); } for (i = 0; i < progs->numfielddefs; i++) { pr_fielddefs[i].type = LittleShort (pr_fielddefs[i].type); if (pr_fielddefs[i].type & DEF_SAVEGLOBAL) SV_Error ("PR_LoadProgs: pr_fielddefs[i].type & DEF_SAVEGLOBAL"); pr_fielddefs[i].ofs = LittleShort (pr_fielddefs[i].ofs); pr_fielddefs[i].s_name = LittleLong (pr_fielddefs[i].s_name); } for (i = 0; i < progs->numglobals; i++) ((int *)pr_globals)[i] = LittleLong (((int *)pr_globals)[i]); #ifdef WITH_NQPROGS PR_InitPatchTables(); #endif // find optional QC-exported functions SpectatorConnect = ED_FindFunctionOffset ("SpectatorConnect"); SpectatorThink = ED_FindFunctionOffset ("SpectatorThink"); SpectatorDisconnect = ED_FindFunctionOffset ("SpectatorDisconnect"); ChatMessage = ED_FindFunctionOffset ("ChatMessage"); UserInfo_Changed = ED_FindFunctionOffset ("UserInfo_Changed"); mod_ConsoleCmd = ED_FindFunctionOffset ("ConsoleCmd"); mod_UserCmd = ED_FindFunctionOffset ("UserCmd"); localinfoChanged = ED_FindFunctionOffset ("localinfoChanged"); GE_ClientCommand = ED_FindFunctionOffset ("GE_ClientCommand"); GE_PausedTic = ED_FindFunctionOffset ("GE_PausedTic"); GE_ShouldPause = ED_FindFunctionOffset ("GE_ShouldPause"); CheckKTPro (); }
/* ================== SVC_DirectConnect A connection request that did not come from the master ================== */ static void SVC_DirectConnect (void) { char userinfo[1024]; static int userid; netadr_t adr; int i; client_t *cl, *newcl; client_t temp; edict_t *ent; int edictnum; const char *s; int clients, spectators; qboolean spectator; q_strlcpy (userinfo, Cmd_Argv(2), sizeof(userinfo)); // check for password or spectator_password s = Info_ValueForKey (userinfo, "spectator"); if (s[0] && strcmp(s, "0")) { if (spectator_password.string[0] && q_strcasecmp(spectator_password.string, "none") && strcmp(spectator_password.string, s) ) { // failed Con_Printf ("%s:spectator password failed\n", NET_AdrToString (net_from)); Netchan_OutOfBandPrint (net_from, "%c\nrequires a spectator password\n\n", A2C_PRINT); return; } Info_SetValueForStarKey (userinfo, "*spectator", "1", MAX_INFO_STRING); spectator = true; Info_RemoveKey (userinfo, "spectator"); // remove passwd } else { s = Info_ValueForKey (userinfo, "password"); if (password.string[0] && q_strcasecmp(password.string, "none") && strcmp(password.string, s) ) { Con_Printf ("%s:password failed\n", NET_AdrToString (net_from)); Netchan_OutOfBandPrint (net_from, "%c\nserver requires a password\n\n", A2C_PRINT); return; } spectator = false; Info_RemoveKey (userinfo, "password"); // remove passwd } adr = net_from; userid++; // so every client gets a unique id newcl = &temp; memset (newcl, 0, sizeof(client_t)); newcl->userid = userid; newcl->portals = atoi(Cmd_Argv(1)); // works properly if (!sv_highchars.integer) { byte *p, *q; for (p = (byte *)newcl->userinfo, q = (byte *)userinfo; *q && p < (byte *)newcl->userinfo + sizeof(newcl->userinfo)-1; q++) { if (*q > 31 && *q <= 127) *p++ = *q; } } else { q_strlcpy (newcl->userinfo, userinfo, sizeof(newcl->userinfo)); } // if there is already a slot for this ip, drop it for (i = 0, cl = svs.clients; i < MAX_CLIENTS; i++, cl++) { if (cl->state == cs_free) continue; if (NET_CompareAdr (adr, cl->netchan.remote_address)) { Con_Printf ("%s:reconnect\n", NET_AdrToString (adr)); SV_DropClient (cl); break; } } // count up the clients and spectators clients = 0; spectators = 0; for (i = 0, cl = svs.clients; i < MAX_CLIENTS; i++, cl++) { if (cl->state == cs_free) continue; if (cl->spectator) spectators++; else clients++; } // if at server limits, refuse connection if (maxclients.integer > MAX_CLIENTS) Cvar_SetValue ("maxclients", MAX_CLIENTS); if (maxspectators.integer > MAX_CLIENTS) Cvar_SetValue ("maxspectators", MAX_CLIENTS); if (maxspectators.integer + maxclients.integer > MAX_CLIENTS) Cvar_SetValue ("maxspectators", MAX_CLIENTS - maxspectators.integer + maxclients.integer); if ( (spectator && spectators >= maxspectators.integer) || (!spectator && clients >= maxclients.integer) ) { Con_Printf ("%s:full connect\n", NET_AdrToString (adr)); Netchan_OutOfBandPrint (adr, "%c\nserver is full\n\n", A2C_PRINT); return; } // find a client slot newcl = NULL; for (i = 0, cl = svs.clients; i < MAX_CLIENTS; i++, cl++) { if (cl->state == cs_free) { newcl = cl; break; } } if (!newcl) { Con_Printf ("WARNING: miscounted available clients\n"); return; } // build a new connection // accept the new client // this is the only place a client_t is ever initialized *newcl = temp; Netchan_OutOfBandPrint (adr, "%c", S2C_CONNECTION ); edictnum = (newcl-svs.clients)+1; Netchan_Setup (&newcl->netchan, adr); newcl->state = cs_connected; SZ_Init (&newcl->datagram, newcl->datagram_buf, sizeof(newcl->datagram_buf)); newcl->datagram.allowoverflow = true; // spectator mode can ONLY be set at join time newcl->spectator = spectator; ent = EDICT_NUM(edictnum); newcl->edict = ent; ED_ClearEdict (ent); // parse some info from the info strings SV_ExtractFromUserinfo (newcl); // JACK: Init the floodprot stuff. for (i = 0; i < 10; i++) newcl->whensaid[i] = 0.0; newcl->whensaidhead = 0; newcl->lockedtill = 0; // call the progs to get default spawn parms for the new client PR_ExecuteProgram (pr_global_struct->SetNewParms); for (i = 0; i < NUM_SPAWN_PARMS; i++) newcl->spawn_parms[i] = (&pr_global_struct->parm1)[i]; if (newcl->spectator) Con_Printf ("Spectator %s connected\n", newcl->name); else Con_DPrintf ("Client %s connected\n", newcl->name); }
/* =============== SV_InitLocal =============== */ static void SV_InitLocal (void) { int i; SV_InitOperatorCommands (); SV_UserInit (); Cvar_RegisterVariable (&developer); if (COM_CheckParm("-developer")) { Cvar_SetValue("developer", 1); Cvar_LockVar ("developer"); } Cvar_RegisterVariable (&sys_nostdout); Cvar_RegisterVariable (&rcon_password); Cvar_RegisterVariable (&password); Cvar_RegisterVariable (&spectator_password); Cvar_RegisterVariable (&sv_mintic); Cvar_RegisterVariable (&sv_maxtic); Cvar_RegisterVariable (&fraglimit); Cvar_RegisterVariable (&timelimit); Cvar_RegisterVariable (&teamplay); Cvar_RegisterVariable (&samelevel); Cvar_RegisterVariable (&maxclients); Cvar_RegisterVariable (&maxspectators); Cvar_RegisterVariable (&hostname); Cvar_RegisterVariable (&skill); Cvar_RegisterVariable (&coop); Cvar_RegisterVariable (&deathmatch); Cvar_RegisterVariable (&randomclass); Cvar_RegisterVariable (&damageScale); Cvar_RegisterVariable (&meleeDamScale); Cvar_RegisterVariable (­Respawn); Cvar_RegisterVariable (&spartanPrint); Cvar_RegisterVariable (&manaScale); Cvar_RegisterVariable (&tomeMode); Cvar_RegisterVariable (&tomeRespawn); Cvar_RegisterVariable (&w2Respawn); Cvar_RegisterVariable (&altRespawn); Cvar_RegisterVariable (&fixedLevel); Cvar_RegisterVariable (&autoItems); Cvar_RegisterVariable (&dmMode); Cvar_RegisterVariable (&easyFourth); Cvar_RegisterVariable (&patternRunner); Cvar_RegisterVariable (&spawn); Cvar_RegisterVariable (&noexit); Cvar_RegisterVariable (&timeout); Cvar_RegisterVariable (&zombietime); Cvar_RegisterVariable (&sv_maxvelocity); Cvar_RegisterVariable (&sv_gravity); Cvar_RegisterVariable (&sv_stopspeed); Cvar_RegisterVariable (&sv_maxspeed); Cvar_RegisterVariable (&sv_spectatormaxspeed); Cvar_RegisterVariable (&sv_accelerate); Cvar_RegisterVariable (&sv_airaccelerate); Cvar_RegisterVariable (&sv_wateraccelerate); Cvar_RegisterVariable (&sv_friction); Cvar_RegisterVariable (&sv_waterfriction); Cvar_RegisterVariable (&sv_aim); Cvar_RegisterVariable (&filterban); Cvar_RegisterVariable (&allow_download); Cvar_RegisterVariable (&allow_download_skins); Cvar_RegisterVariable (&allow_download_models); Cvar_RegisterVariable (&allow_download_sounds); Cvar_RegisterVariable (&allow_download_maps); Cvar_RegisterVariable (&sv_highchars); Cvar_RegisterVariable (&sv_phs); Cvar_RegisterVariable (&sv_namedistance); Cvar_RegisterVariable (&sv_ce_scale); Cvar_RegisterVariable (&sv_ce_max_size); Cmd_AddCommand ("addip", SV_AddIP_f); Cmd_AddCommand ("removeip", SV_RemoveIP_f); Cmd_AddCommand ("listip", SV_ListIP_f); Cmd_AddCommand ("writeip", SV_WriteIP_f); for (i = 0; i < MAX_MODELS; i++) sprintf (localmodels[i], "*%i", i); Info_SetValueForStarKey (svs.info, "*version", va("%4.2f", ENGINE_VERSION), MAX_SERVERINFO_STRING); // init fraglog stuff svs.logsequence = 1; svs.logtime = realtime; SZ_Init (&svs.log[0], svs.log_buf[0], sizeof(svs.log_buf[0])); SZ_Init (&svs.log[1], svs.log_buf[1], sizeof(svs.log_buf[1])); svs.log[0].allowoverflow = true; svs.log[1].allowoverflow = true; }
void SV_InitOperatorCommands (void) { if (COM_CheckParm ("-cheats")) { sv_allow_cheats = true; Info_SetValueForStarKey (svs.info, "*cheats", "ON", 0); } Cmd_AddCommand ("fraglogfile", SV_Fraglogfile_f, "Enables logging of kills " "to frag_##.log"); Cmd_AddCommand ("snap", SV_Snap_f, "Take a screenshot of userid"); Cmd_AddCommand ("snapall", SV_SnapAll_f, "Take a screenshot of all users"); Cmd_AddCommand ("kick", SV_Kick_f, "Remove a user from the server (kick " "userid)"); Cmd_AddCommand ("status", SV_Status_f, "Report information on the current " "connected clients and the server - displays userids"); Cmd_AddCommand ("map", SV_Map_f, "Change to a new map (map mapname)"); Cmd_AddCommand ("setmaster", SV_SetMaster_f, "Lists the server with up to " "eight masters.\n" "When a server is listed with a master, the master is " "aware of the server's IP address and port and it is added " "to the\n" "list of current servers connected to a master. A " "heartbeat is sent to the master from the server to " "indicated that the\n" "server is still running and alive.\n\n" "Examples:\n" "setmaster 192.246.40.12:27002\n" "setmaster 192.246.40.12:27002 192.246.40.12:27004"); Cmd_AddCommand ("heartbeat", SV_Heartbeat_f, "Force a heartbeat to be sent " "to the master server.\n" "A heartbeat tells the Master the server's IP address and " "that it is still alive."); Cmd_AddCommand ("restart", SV_Restart_f, "Restart the server (with shell " "support)"); Cmd_AddCommand ("quit", SV_Quit_f, "Shut down the server"); Cmd_AddCommand ("god", SV_God_f, "Toggle god cheat to userid (god userid) " "Requires cheats are enabled"); Cmd_AddCommand ("give", SV_Give_f, "Give userid items, or health.\n" "Items: 1 Axe, 2 Shotgun, 3 Double-Barrelled Shotgun, 4 " "Nailgun, 5 Super Nailgun, 6 Grenade Launcher, 7 Rocket " "Launcher,\n" "8 ThunderBolt, C Cells, H Health, N Nails, R Rockets, S " "Shells. Requires cheats to be enabled. (give userid item " "amount)"); Cmd_AddCommand ("noclip", SV_Noclip_f, "Toggle no clipping cheat for " "userid. Requires cheats to be enabled. (noclip userid)"); Cmd_AddCommand ("serverinfo", SV_Serverinfo_f, "Reports or sets " "information about server.\n" "The information stored in this space is broadcast on the " "network to all players.\n" "Values:\n" "dq - Drop Quad Damage when a player dies.\n" "dr - Drop Ring of Shadows when a player dies.\n" "rj - Sets the multiplier rate for splash damage kick.\n" "needpass - Displays the passwords enabled on the server.\n" "watervis - Toggle the use of r_watervis by OpenGL " "clients.\n" "Note: Keys with (*) in front cannot be changed. Maximum " "key size cannot exceed 64-bytes.\n" "Maximum size for all keys cannot exceed 512-bytes.\n" "(serverinfo key value)"); Cmd_AddCommand ("localinfo", SV_Localinfo_f, "Shows or sets localinfo " "variables.\n" "Useful for mod programmers who need to allow the admin to " "change settings.\n" "This is an alternative storage space to the serverinfo " "space for mod variables.\n" "The variables stored in this space are not broadcast on " "the network.\n" "This space also has a 32-kilobyte limit which is much " "greater then the 512-byte limit on the serverinfo space.\n" "Special Keys: (current map) (next map) - Using this " "combination will allow the creation of a custom map cycle " "without editing code.\n\n" "Example:\n" "localinfo dm2 dm4\n" "localinfo dm4 dm6\n" "localinfo dm6 dm2\n" "(localinfo key value)"); Cmd_AddCommand ("user", SV_User_f, "Report information about the user " "(user userid)"); Cmd_AddCommand ("sv_gamedir", SV_Gamedir, "Displays or determines the " "value of the serverinfo *gamedir variable.\n" "Note: Useful when the physical gamedir directory has a " "different name than the widely accepted gamedir " "directory.\n" "Example:\n" "gamedir tf2_5; sv_gamedir fortress\n" "gamedir ctf4_2; sv_gamedir ctf\n" "(sv_gamedir dirname)"); Cmd_AddCommand ("floodprot", SV_Floodprot_f, "Sets the options for flood " "protection.\n" "Default: 4 4 10\n" "(floodprot (number of messages) (number of seconds) " "(silence time in seconds))"); Cmd_AddCommand ("floodprotmsg", SV_Floodprotmsg_f, "Sets the message " "displayed after flood protection is invoked (floodprotmsg " "message)"); Cmd_AddCommand ("maplist", Con_Maplist_f, "List all maps on the server"); Cmd_AddCommand ("say", SV_ConSay_f, "Say something to everyone on the " "server. Will show up as the name 'Console' (or 'Admin') " "in game"); Cmd_AddCommand ("sayinfo", SV_ConSay_Info_f, "Say something to everyone on " "the server. Will show up as the name 'Info' in game"); Cmd_AddCommand ("tell", SV_Tell_f, "Say something to a specific user on " "the server. Will show up as the name 'Console' (or " "'Admin') in game"); Cmd_AddCommand ("ban", SV_Ban_f, "ban a player for a specified time"); Cmd_AddCommand ("cuff", SV_Cuff_f, "\"hand-cuff\" a player for a " "specified time"); Cmd_AddCommand ("mute", SV_Mute_f, "silience a player for a specified " "time"); Cmd_AddCommand ("match", SV_Match_f, "matches nicks as ban/cuff/mute " "commands do, so you can check safely"); // poor description sv_leetnickmatch = Cvar_Get ("sv_3133735_7h4n_7h0u", "1", CVAR_NONE, NULL, "Match '1' as 'i' and such in nicks"); }
/* ================ SV_SpawnServer Change the server to a new map, taking all connected clients along with it. This is only called from the SV_Map_f() function. ================ */ void SV_SpawnServer (char *mapname, qbool devmap) { char *entitystring; edict_t *ent; int i; extern qbool sv_allow_cheats; extern cvar_t sv_cheats; Com_DPrintf ("SpawnServer: %s\n", mapname); NET_InitServer(); SV_SaveSpawnparms (); svs.spawncount++; // any partially connected client will be restarted sv.state = ss_dead; com_serveractive = false; Cvar_ForceSet (&sv_paused, "0"); Host_ClearMemory(); if (deathmatch.value) Cvar_Set (&coop, "0"); current_skill = (int)(skill.value + 0.5); if (current_skill < 0) current_skill = 0; if (current_skill > 3) current_skill = 3; Cvar_Set (&skill, va("%d", (int)current_skill)); if ((sv_cheats.value || devmap) && !sv_allow_cheats) { sv_allow_cheats = true; Info_SetValueForStarKey (svs.info, "*cheats", "ON", MAX_SERVERINFO_STRING); } else if ((!sv_cheats.value && !devmap) && sv_allow_cheats) { sv_allow_cheats = false; Info_SetValueForStarKey (svs.info, "*cheats", "", MAX_SERVERINFO_STRING); } // wipe the entire per-level structure memset (&sv, 0, sizeof(sv)); SZ_Init (&sv.datagram, sv.datagram_buf, sizeof(sv.datagram_buf)); sv.datagram.allowoverflow = true; SZ_Init (&sv.reliable_datagram, sv.reliable_datagram_buf, sizeof(sv.reliable_datagram_buf)); SZ_Init (&sv.multicast, sv.multicast_buf, sizeof(sv.multicast_buf)); SZ_Init (&sv.signon, sv.signon_buffers[0], sizeof(sv.signon_buffers[0])); sv.num_signon_buffers = 1; // load progs to get entity field count // which determines how big each edict is PR_LoadProgs (); // allocate edicts sv.edicts = (edict_t *) Hunk_AllocName (SV_MAX_EDICTS*pr_edict_size, "edicts"); // leave slots at start for clients only sv.num_edicts = MAX_CLIENTS+1; for (i = 0; i < MAX_CLIENTS; i++) { ent = EDICT_NUM(i+1); svs.clients[i].edict = ent; svs.clients[i].old_frags = 0; //ZOID - make sure we update frags right } sv.time = 1.0; #ifndef SERVERONLY { void R_PreMapLoad (char *mapname); R_PreMapLoad (mapname); } #endif strlcpy (sv.mapname, mapname, sizeof(sv.mapname)); Cvar_ForceSet (&host_mapname, mapname); snprintf (sv.modelname, sizeof(sv.modelname), "maps/%s.bsp", mapname); sv.worldmodel = CM_LoadMap (sv.modelname, false, &sv.map_checksum, &sv.map_checksum2); // clear physics interaction links SV_ClearWorld (); sv.sound_precache[0] = pr_strings; sv.model_precache[0] = pr_strings; sv.model_precache[1] = sv.modelname; sv.models[1] = sv.worldmodel; for (i = 1; i < CM_NumInlineModels(); i++) { sv.model_precache[1+i] = localmodels[i]; sv.models[i + 1] = CM_InlineModel (localmodels[i]); } //check player/eyes models for hacks sv.model_player_checksum = SV_CheckModel("progs/player.mdl"); sv.eyes_player_checksum = SV_CheckModel("progs/eyes.mdl"); // spawn the rest of the entities on the map // precache and static commands can be issued during map initialization sv.state = ss_loading; com_serveractive = true; ent = EDICT_NUM(0); ent->free = false; ent->v.model = PR_SetString(sv.modelname); ent->v.modelindex = 1; // world model ent->v.solid = SOLID_BSP; ent->v.movetype = MOVETYPE_PUSH; pr_global_struct->mapname = PR_SetString(sv.mapname); // serverflags are for cross level information (sigils) pr_global_struct->serverflags = svs.serverflags; // run the frame start qc function to let progs check cvars SV_ProgStartFrame (); // load and spawn all other entities entitystring = NULL; if ((int) sv_loadentfiles.value) { int filesize; entitystring = (char *)FS_LoadHunkFile (va("maps/%s.ent", sv.mapname), &filesize); if (entitystring) { Com_DPrintf ("Using entfile maps/%s.ent\n", sv.mapname); Info_SetValueForStarKey (svs.info, "*entfile", va("%i", CRC_Block((byte *)entitystring, filesize)), MAX_SERVERINFO_STRING); } } if (!entitystring) { Info_SetValueForStarKey (svs.info, "*entfile", "", MAX_SERVERINFO_STRING); entitystring = CM_EntityString(); } ED_LoadFromFile (entitystring); // look up some model indexes for specialized message compression SV_FindModelNumbers (); // all spawning is completed, any further precache statements // or prog writes to the signon message are errors sv.state = ss_active; // run two frames to allow everything to settle SV_Physics (); sv.time += 0.1; SV_Physics (); sv.time += 0.1; sv.old_time = sv.time; // save movement vars SV_SetMoveVars(); // create a baseline for more efficient communications SV_CreateBaseline (); sv.signon_buffer_size[sv.num_signon_buffers - 1] = sv.signon.cursize; Info_SetValueForKey (svs.info, "map", sv.mapname, MAX_SERVERINFO_STRING); Com_DPrintf ("Server spawned.\n"); #ifndef SERVERONLY if (!dedicated) { void CL_ClearState (void); CL_ClearState (); } #endif }
/* =============== SV_InitLocal =============== */ void SV_InitLocal (void) { int i; extern cvar_t sv_spectalk; extern cvar_t sv_mapcheck; extern cvar_t sv_minping; extern cvar_t sv_maxpitch; extern cvar_t sv_minpitch; extern cvar_t sv_nailhack; extern cvar_t sv_loadentfiles; extern cvar_t sv_maxvelocity; extern cvar_t sv_gravity; extern cvar_t pm_stopspeed; extern cvar_t pm_spectatormaxspeed; extern cvar_t pm_accelerate; extern cvar_t pm_airaccelerate; extern cvar_t pm_wateraccelerate; extern cvar_t pm_friction; extern cvar_t pm_waterfriction; extern cvar_t pm_bunnyspeedcap; extern cvar_t pm_ktjump; extern cvar_t pm_slidefix; extern cvar_t pm_airstep; extern cvar_t pm_pground; packet_t *packet_freeblock; // initialise delayed packet free block SV_InitOperatorCommands (); Cvar_Register (&sv_rconPassword); Cvar_Register (&sv_password); Cvar_Register (&sv_spectatorPassword); Cvar_Register (&sv_phs); Cvar_Register (&sv_paused); Cvar_Register (&sv_pausable); Cmd_AddLegacyCommand ("pausable", "sv_pausable"); Cvar_Register (&sv_nailhack); Cvar_Register (&sv_maxrate); Cvar_Register (&sv_fastconnect); Cvar_Register (&sv_loadentfiles); if (!dedicated) sv_mintic.string = "0"; // a value of 0 will tie physics tics to screen updates Cvar_Register (&sv_mintic); Cvar_Register (&sv_maxtic); Cvar_Register (&sv_timeout); Cmd_AddLegacyCommand ("timeout", "sv_timeout"); Cvar_Register (&sv_zombietime); Cmd_AddLegacyCommand ("zombietime", "sv_zombietime"); Cvar_Register (&sv_spectalk); Cvar_Register (&sv_mapcheck); if (dedicated) Cvar_Register (&sv_minping); Cvar_Register (&sv_maxpitch); Cvar_Register (&sv_minpitch); Cvar_Register (&deathmatch); Cvar_Register (&teamplay); Cvar_Register (&skill); Cvar_Register (&coop); Cvar_Register (&fraglimit); Cvar_Register (&timelimit); Cvar_Register (&samelevel); Cvar_Register (&maxclients); Cvar_Register (&maxspectators); Cvar_Register (&hostname); Cvar_Register (&watervis); Cvar_Register (&sv_maxvelocity); Cvar_Register (&sv_gravity); Cvar_Register (&pm_stopspeed); Cvar_Register (&pm_maxspeed); Cvar_Register (&pm_spectatormaxspeed); Cvar_Register (&pm_accelerate); Cvar_Register (&pm_airaccelerate); Cvar_Register (&pm_wateraccelerate); Cvar_Register (&pm_friction); Cvar_Register (&pm_waterfriction); Cvar_Register (&pm_bunnyspeedcap); Cvar_Register (&pm_ktjump); Cvar_Register (&pm_slidefix); Cvar_Register (&pm_airstep); Cvar_Register (&pm_pground); Cvar_Register (&allow_download); Cvar_Register (&allow_download_skins); Cvar_Register (&allow_download_models); Cvar_Register (&allow_download_sounds); Cvar_Register (&allow_download_maps); Cvar_Register (&allow_download_pakmaps); Cvar_Register (&allow_download_gfx); Cvar_Register (&allow_download_other); Cvar_Register (&filterban); Cmd_AddCommand ("addip", SV_AddIP_f); Cmd_AddCommand ("removeip", SV_RemoveIP_f); Cmd_AddCommand ("listip", SV_ListIP_f); Cmd_AddCommand ("writeip", SV_WriteIP_f); for (i=1 ; i<MAX_MODELS ; i++) sprintf (localmodels[i], "*%i", i); Info_SetValueForStarKey (svs.info, "*version", va(PROGRAM " %s", VersionString()), MAX_SERVERINFO_STRING); Info_SetValueForStarKey (svs.info, "*z_ext", va("%i", SUPPORTED_EXTENSIONS), MAX_SERVERINFO_STRING); #ifdef VWEP_TEST Info_SetValueForStarKey (svs.info, "*vwtest", "1", MAX_SERVERINFO_STRING); #endif if (strcmp(com_gamedirfile, "qw")) Info_SetValueForStarKey (svs.info, "*gamedir", com_gamedirfile, MAX_SERVERINFO_STRING); // init fraglog stuff svs.logsequence = 1; svs.logtime = svs.realtime; SZ_Init (&svs.log[0], svs.log_buf[0], sizeof(svs.log_buf[0])); svs.log[0].allowoverflow = true; SZ_Init (&svs.log[1], svs.log_buf[1], sizeof(svs.log_buf[1])); svs.log[1].allowoverflow = true; packet_freeblock = Hunk_AllocName(MAX_DELAYED_PACKETS * sizeof(packet_t), "delayed_packets"); for (i = 0; i < MAX_DELAYED_PACKETS; i++) { SZ_Init (&packet_freeblock[i].msg, packet_freeblock[i].buf, sizeof(packet_freeblock[i].buf)); packet_freeblock[i].next = &packet_freeblock[i + 1]; } packet_freeblock[MAX_DELAYED_PACKETS - 1].next = NULL; svs.free_packets = &packet_freeblock[0]; #ifdef MAUTH // Set up queues for temporary auth tokens and auth'd clients... authtokq.maxlen = MAX_AUTH_TOK_QUEUE; authtokq.curlen = 0; authtokq.start = NULL; authclientq.maxlen = MAX_AUTH_CLIENT_QUEUE; authclientq.curlen = 0; authclientq.start = NULL; #endif }
qbool VM_LoadBytecode( vm_t * vm, sys_callex_t syscall1 ) { char name[MAX_OSPATH]; byte *buff; vmHeader_t *header; qvm_t *qvm; char num[32]; int filesize; snprintf( name, sizeof( name ), "%s.qvm", vm->name ); Con_DPrintf( "VM_LoadBytecode: load %s\n", name ); buff = FS_LoadTempFile( name , &filesize ); if ( !buff ) return false; // add qvm crc to the serverinfo snprintf( num, sizeof(num), "%i", CRC_Block( ( byte * ) buff, filesize ) ); Info_SetValueForStarKey( svs.info, "*progs", num, MAX_SERVERINFO_STRING ); header = ( vmHeader_t * ) buff; header->vmMagic = LittleLong( header->vmMagic ); header->instructionCount = LittleLong( header->instructionCount ); header->codeOffset = LittleLong( header->codeOffset ); header->codeLength = LittleLong( header->codeLength ); header->dataOffset = LittleLong( header->dataOffset ); header->dataLength = LittleLong( header->dataLength ); header->litLength = LittleLong( header->litLength ); header->bssLength = LittleLong( header->bssLength ); // check file if ( header->vmMagic != VM_MAGIC || header->instructionCount <= 0 || header->codeLength <= 0 ) { return false; } // create vitrual machine if(vm->hInst) qvm = (qvm_t *)vm->hInst; else qvm = (qvm_t *) Q_malloc (sizeof (qvm_t)); qvm->len_cs = header->instructionCount + 1; //bad opcode padding. qvm->len_ds = header->dataOffset + header->litLength + header->bssLength; //align ds qvm->ds_mask = 1; while( qvm->ds_mask < qvm->len_ds) qvm->ds_mask<<=1; qvm->len_ds = qvm->ds_mask; qvm->ds_mask--; qvm->len_ss = 0x10000; // default by q3asm if ( qvm->len_ds < qvm->len_ss ) Sys_Error( "VM_LoadBytecode: stacksize greater than data segment" ); qvm->cs = ( qvm_instruction_t * ) Hunk_AllocName( qvm->len_cs * sizeof( qvm_instruction_t ), "qvmcode" ); qvm->ds = (byte *) Hunk_AllocName( qvm->len_ds, "qvmdata" ); qvm->ss = qvm->ds + qvm->len_ds - qvm->len_ss; // setup registers qvm->PC = 0; qvm->SP = 0; qvm->LP = qvm->len_ds - sizeof(int); qvm->cycles = 0; qvm->reenter = 0; qvm->syscall = syscall1; // load instructions { byte *src = buff + header->codeOffset; qvm_instruction_t *dst = qvm->cs; opcode_t op; int i; for ( i = 0; i < header->instructionCount; i++, dst++ ) { op = (opcode_t) *src++; dst->opcode = op; switch ( op ) { case OP_ARG: dst->parm._int = ( int ) *src++; break; case OP_ENTER: case OP_LEAVE: case OP_CONST: case OP_LOCAL: case OP_EQ: case OP_NE: case OP_LTI: case OP_LEI: case OP_GTI: case OP_GEI: case OP_LTU: case OP_LEU: case OP_GTU: case OP_GEU: case OP_EQF: case OP_NEF: case OP_LTF: case OP_LEF: case OP_GTF: case OP_GEF: case OP_BLOCK_COPY: dst->parm._int = LittleLong( *( int * ) src ); src += 4; break; default: dst->parm._int = 0; break; } } dst->opcode = OP_BREAK; dst->parm._int = 0; } // load data segment { int *src = ( int * ) ( buff + header->dataOffset ); int *dst = ( int * ) qvm->ds; int i; for ( i = 0; i < header->dataLength / 4; i++ ) *dst++ = LittleLong( *src++ ); memcpy( dst, src, header->litLength ); } LoadMapFile( qvm, vm->name ); vm->type = VM_BYTECODE; vm->hInst = qvm; return true; }
/* ================== SVC_DirectConnect A connection request that did not come from the master ================== */ void SVC_DirectConnect (void) { char userinfo[1024]; netadr_t adr; int i; client_t *cl, *newcl; edict_t *ent; int edictnum; char *s; int clients, spectators; qbool spectator; int qport; int version; int challenge; version = atoi(Cmd_Argv(1)); if (version != PROTOCOL_VERSION) { Netchan_OutOfBandPrint (NS_SERVER, net_from, "%c\nServer is version %4.2f.\n", A2C_PRINT, QW_VERSION); Com_Printf ("* rejected connect from version %i\n", version); return; } qport = atoi(Cmd_Argv(2)); challenge = atoi(Cmd_Argv(3)); // note an extra byte is needed to replace spectator key strlcpy (userinfo, Cmd_Argv(4), sizeof(userinfo)-1); // see if the challenge is valid if (net_from.type != NA_LOOPBACK) { for (i=0 ; i<MAX_CHALLENGES ; i++) { if (NET_CompareBaseAdr (net_from, svs.challenges[i].adr)) { if (challenge == svs.challenges[i].challenge) break; // good Netchan_OutOfBandPrint (NS_SERVER, net_from, "%c\nBad challenge.\n", A2C_PRINT); return; } } if (i == MAX_CHALLENGES) { Netchan_OutOfBandPrint (NS_SERVER, net_from, "%c\nNo challenge for address.\n", A2C_PRINT); return; } } // check for password or spectator_password s = Info_ValueForKey (userinfo, "spectator"); if (s[0] && strcmp(s, "0")) { if (sv_spectatorPassword.string[0] && Q_stricmp(sv_spectatorPassword.string, "none") && strcmp(sv_spectatorPassword.string, s) ) { // failed Com_Printf ("%s:spectator password failed\n", NET_AdrToString (net_from)); Netchan_OutOfBandPrint (NS_SERVER, net_from, "%c\nrequires a spectator password\n\n", A2C_PRINT); return; } Info_RemoveKey (userinfo, "spectator"); Info_SetValueForStarKey (userinfo, "*spectator", "1", MAX_INFO_STRING); spectator = true; } else { s = Info_ValueForKey (userinfo, "password"); if (sv_password.string[0] && Q_stricmp(sv_password.string, "none") && strcmp(sv_password.string, s) ) { Com_Printf ("%s:password failed\n", NET_AdrToString (net_from)); Netchan_OutOfBandPrint (NS_SERVER, net_from, "%c\nserver requires a password\n\n", A2C_PRINT); return; } spectator = false; Info_RemoveKey (userinfo, "password"); } #ifdef MAUTH // Check that the client is allowed to connect... if( net_from.type != NA_LOOPBACK && !COM_CheckParm("-nomauth") ) { authclient_t *authclient; // Try the auth token queue first... authclient = SV_AuthListFind(&authtokq, Info_ValueForKey(userinfo, "name")); if( authclient == NULL ) { // Fall back to checking if they had already connected and are in the // client queue already (i.e. were on here before a map change)... authclient = SV_AuthListFind(&authclientq, Info_ValueForKey(userinfo, "name")); if( authclient == NULL ) { // FIXME drop with reason Com_Printf ("MAUTH: Client %s not in a queue; connect refused.\n", Info_ValueForKey(userinfo, "name")); return; } } else { // They're valid, so move them to the main client queue from the // auth cache queue... SV_AuthListMove(&authtokq, &authclientq, authclient); } // Move to auth'd clients queue if they're valid... if( !authclient->valid ) { // FIXME drop with reason Com_Printf ("MAUTH: Client %s not validated yet; connect refused.\n", Info_ValueForKey(userinfo, "name")); return; } //SV_AuthListPrint(&authtokq); //SV_AuthListPrint(&authclientq); Com_Printf ("MAUTH: Client %s connection allowed.\n", Info_ValueForKey(userinfo, "name")); } else { Com_Printf("MAUTH: loopback or disabled; allowing client connection.\n"); } #endif adr = net_from; // if there is already a slot for this ip, reuse it for (i = 0, cl = svs.clients; i < MAX_CLIENTS; i++, cl++) { if (cl->state == cs_free) continue; if (NET_CompareBaseAdr (adr, cl->netchan.remote_address) && ( cl->netchan.qport == qport || adr.port == cl->netchan.remote_address.port )) { if (cl->state == cs_connected) { Com_Printf ("%s:dup connect\n", NET_AdrToString (adr)); return; } Com_Printf ("%s:reconnect\n", NET_AdrToString (adr)); if (cl->state == cs_spawned) { SV_DropClient (cl); SV_ClearReliable (cl); // don't send the disconnect } cl->state = cs_free; break; } } // count up the clients and spectators and find an empty client slot clients = spectators = 0; newcl = NULL; for (i = 0, cl = svs.clients; i < MAX_CLIENTS; i++,cl++) { if (cl->state == cs_free) { if (!newcl) newcl = cl; // grab first available slot continue; } if (cl->spectator) spectators++; else clients++; } // if at server limits, refuse connection if ( (spectator && spectators >= (int)maxspectators.value) || (!spectator && clients >= (int)maxclients.value) || !newcl) { Com_Printf ("%s:full connect\n", NET_AdrToString (adr)); Netchan_OutOfBandPrint (NS_SERVER, adr, "%c\nserver is full\n\n", A2C_PRINT); return; } // build a new connection // accept the new client // this is the only place a client_t is ever initialized memset (newcl, 0, sizeof(*newcl)); newcl->userid = SV_GenerateUserID(); strlcpy (newcl->userinfo, userinfo, sizeof(newcl->userinfo)); Netchan_OutOfBandPrint (NS_SERVER, adr, "%c", S2C_CONNECTION ); Netchan_Setup (NS_SERVER, &newcl->netchan, adr, qport); newcl->state = cs_connected; SZ_Init (&newcl->datagram, newcl->datagram_buf, sizeof(newcl->datagram_buf)); newcl->datagram.allowoverflow = true; // spectator mode can ONLY be set at join time newcl->spectator = spectator; // extract extensions bits newcl->extensions = atoi(Info_ValueForKey(newcl->userinfo, "*z_ext")); Info_RemoveKey (newcl->userinfo, "*z_ext"); #ifdef VWEP_TEST newcl->extensions |= atoi(Info_ValueForKey(newcl->userinfo, "*vwtest")) ? Z_EXT_VWEP : 0; Info_RemoveKey (newcl->userinfo, "*vwtest"); #endif // See if the client is using a proxy. The best test I can come up with for now... newcl->uses_proxy = *Info_ValueForKey(newcl->userinfo, "Qizmo") ? true : false; edictnum = (newcl - svs.clients) + 1; ent = EDICT_NUM(edictnum); ent->inuse = true; newcl->edict = ent; // parse some info from the info strings SV_ExtractFromUserinfo (newcl); // JACK: Init the floodprot stuff. for (i=0; i<10; i++) newcl->whensaid[i] = 0.0; newcl->whensaidhead = 0; newcl->lockedtill = 0; // call the progs to get default spawn parms for the new client PR_ExecuteProgram (pr_global_struct->SetNewParms); for (i=0 ; i<NUM_SPAWN_PARMS ; i++) newcl->spawn_parms[i] = (&pr_global_struct->parm1)[i]; if (newcl->spectator) Com_Printf ("Spectator %s connected\n", newcl->name); else Com_DPrintf ("Client %s connected\n", newcl->name); newcl->sendinfo = true; }
/* ================ SV_SpawnServer Change the server to a new map, taking all connected clients along with it. This is only called from the SV_Map_f() function. ================ */ void SV_SpawnServer (char *mapname, qbool devmap, char* entityfile) { extern func_t ED_FindFunctionOffset (char *name); edict_t *ent; int i; extern cvar_t sv_loadentfiles, sv_loadentfiles_dir; char *entitystring; char oldmap[MAP_NAME_LEN]; extern qbool sv_allow_cheats; extern cvar_t sv_cheats, sv_paused, sv_bigcoords; #ifndef SERVERONLY extern void CL_ClearState (void); #endif // store old map name snprintf (oldmap, MAP_NAME_LEN, "%s", sv.mapname); Con_DPrintf ("SpawnServer: %s\n",mapname); #ifndef SERVERONLY // As client+server we do it here. // As serveronly we do it in NET_Init(). NET_InitServer(); #endif SV_SaveSpawnparms (); SV_LoadAccounts(); #ifdef USE_PR2 // remove bot clients for (i = 0; i < MAX_CLIENTS; i++) { if( sv_vm && svs.clients[i].isBot ) { svs.clients[i].old_frags = 0; svs.clients[i].edict->v.frags = 0.0; svs.clients[i].name[0] = 0; svs.clients[i].state = cs_free; Info_RemoveAll(&svs.clients[i]._userinfo_ctx_); Info_RemoveAll(&svs.clients[i]._userinfoshort_ctx_); SV_FullClientUpdate(&svs.clients[i], &sv.reliable_datagram); svs.clients[i].isBot = 0; } } #endif // Shutdown game. PR_GameShutDown(); PR_UnLoadProgs(); svs.spawncount++; // any partially connected client will be restarted #ifndef SERVERONLY com_serveractive = false; #endif sv.state = ss_dead; sv.paused = false; Cvar_SetROM(&sv_paused, "0"); Host_ClearMemory(); #ifdef FTE_PEXT_FLOATCOORDS if (sv_bigcoords.value) { msg_coordsize = 4; msg_anglesize = 2; } else { msg_coordsize = 2; msg_anglesize = 1; } #endif if ((int)coop.value) Cvar_Set (&deathmatch, "0"); current_skill = (int) (skill.value + 0.5); if (current_skill < 0) current_skill = 0; Cvar_Set (&skill, va("%d", current_skill)); if (current_skill > 3) current_skill = 3; if ((sv_cheats.value || devmap) && !sv_allow_cheats) { sv_allow_cheats = true; Info_SetValueForStarKey (svs.info, "*cheats", "ON", MAX_SERVERINFO_STRING); } else if ((!sv_cheats.value && !devmap) && sv_allow_cheats) { sv_allow_cheats = false; Info_SetValueForStarKey (svs.info, "*cheats", "", MAX_SERVERINFO_STRING); } // wipe the entire per-level structure // NOTE: this also set sv.mvdrecording to false, so calling SV_MVD_Record() at end of function memset (&sv, 0, sizeof(sv)); sv.datagram.maxsize = sizeof(sv.datagram_buf); sv.datagram.data = sv.datagram_buf; sv.datagram.allowoverflow = true; sv.reliable_datagram.maxsize = sizeof(sv.reliable_datagram_buf); sv.reliable_datagram.data = sv.reliable_datagram_buf; sv.multicast.maxsize = sizeof(sv.multicast_buf); sv.multicast.data = sv.multicast_buf; sv.signon.maxsize = sizeof(sv.signon_buffers[0]); sv.signon.data = sv.signon_buffers[0]; sv.num_signon_buffers = 1; sv.time = 1.0; // load progs to get entity field count // which determines how big each edict is // and allocate edicts PR_LoadProgs (); #ifdef WITH_NQPROGS PR_InitPatchTables(); #endif PR_InitProg(); for (i = 0; i < MAX_EDICTS; i++) { ent = EDICT_NUM(i); ent->e = &sv.sv_edicts[i]; // assigning ->e field in each edict_t ent->e->entnum = i; ent->e->area.ed = ent; // yeah, pretty funny, but this help to find which edict_t own this area (link_t) } fofs_items2 = ED_FindFieldOffset ("items2"); // ZQ_ITEMS2 extension fofs_maxspeed = ED_FindFieldOffset ("maxspeed"); fofs_gravity = ED_FindFieldOffset ("gravity"); fofs_movement = ED_FindFieldOffset ("movement"); fofs_vw_index = ED_FindFieldOffset ("vw_index"); fofs_hideentity = ED_FindFieldOffset ("hideentity"); fofs_trackent = ED_FindFieldOffset ("trackent"); // find optional QC-exported functions. // we have it here, so we set it to NULL in case of PR2 progs. mod_SpectatorConnect = ED_FindFunctionOffset ("SpectatorConnect"); mod_SpectatorThink = ED_FindFunctionOffset ("SpectatorThink"); mod_SpectatorDisconnect = ED_FindFunctionOffset ("SpectatorDisconnect"); mod_ChatMessage = ED_FindFunctionOffset ("ChatMessage"); mod_UserInfo_Changed = ED_FindFunctionOffset ("UserInfo_Changed"); mod_ConsoleCmd = ED_FindFunctionOffset ("ConsoleCmd"); mod_UserCmd = ED_FindFunctionOffset ("UserCmd"); mod_localinfoChanged = ED_FindFunctionOffset ("localinfoChanged"); GE_ClientCommand = ED_FindFunctionOffset ("GE_ClientCommand"); GE_PausedTic = ED_FindFunctionOffset ("GE_PausedTic"); GE_ShouldPause = ED_FindFunctionOffset ("GE_ShouldPause"); // leave slots at start for clients only sv.num_edicts = MAX_CLIENTS+1; for (i=0 ; i<MAX_CLIENTS ; i++) { ent = EDICT_NUM(i+1); // restore client name. ent->v.netname = PR_SetString(svs.clients[i].name); // reserve edict. svs.clients[i].edict = ent; //ZOID - make sure we update frags right svs.clients[i].old_frags = 0; } // fill sv.mapname and sv.modelname with new map name strlcpy (sv.mapname, mapname, sizeof(sv.mapname)); snprintf (sv.modelname, sizeof(sv.modelname), "maps/%s.bsp", sv.mapname); #ifndef SERVERONLY // set cvar Cvar_ForceSet (&host_mapname, mapname); #endif if (!(sv.worldmodel = CM_LoadMap (sv.modelname, false, &sv.map_checksum, &sv.map_checksum2))) // true if bad map { Con_Printf ("Cant load map %s, falling back to %s\n", mapname, oldmap); // fill mapname, sv.mapname and sv.modelname with old map name strlcpy (sv.mapname, oldmap, sizeof(sv.mapname)); snprintf (sv.modelname, sizeof(sv.modelname), "maps/%s.bsp", sv.mapname); mapname = oldmap; // and re-load old map sv.worldmodel = CM_LoadMap (sv.modelname, false, &sv.map_checksum, &sv.map_checksum2); // this should never happen if (!sv.worldmodel) SV_Error ("CM_LoadMap: bad map"); } sv.map_checksum2 = Com_TranslateMapChecksum (sv.mapname, sv.map_checksum2); SV_ClearWorld (); // clear physics interaction links #ifdef USE_PR2 if ( sv_vm ) { sv.sound_precache[0] = ""; sv.model_precache[0] = ""; } else #endif { sv.sound_precache[0] = pr_strings; sv.model_precache[0] = pr_strings; } sv.model_precache[1] = sv.modelname; sv.models[1] = sv.worldmodel; for (i=1 ; i< CM_NumInlineModels() ; i++) { sv.model_precache[1+i] = localmodels[i]; sv.models[i+1] = CM_InlineModel (localmodels[i]); } //check player/eyes models for hacks sv.model_player_checksum = SV_CheckModel("progs/player.mdl"); sv.model_newplayer_checksum = SV_CheckModel("progs/newplayer.mdl"); sv.eyes_player_checksum = SV_CheckModel("progs/eyes.mdl"); // // spawn the rest of the entities on the map // // precache and static commands can be issued during // map initialization sv.state = ss_loading; #ifndef SERVERONLY com_serveractive = true; #endif ent = EDICT_NUM(0); ent->e->free = false; ent->v.model = PR_SetString(sv.modelname); ent->v.modelindex = 1; // world model ent->v.solid = SOLID_BSP; ent->v.movetype = MOVETYPE_PUSH; // information about the server ent->v.netname = PR_SetString(VersionStringFull()); ent->v.targetname = PR_SetString(SERVER_NAME); ent->v.impulse = VERSION_NUM; ent->v.items = pr_numbuiltins - 1; PR_GLOBAL(mapname) = PR_SetString(sv.mapname); // serverflags are for cross level information (sigils) PR_GLOBAL(serverflags) = svs.serverflags; if (pr_nqprogs) { pr_globals[35] = deathmatch.value; pr_globals[36] = coop.value; pr_globals[37] = teamplay.value; NQP_Reset (); } if (pr_nqprogs) { // register the cvars that NetQuake provides for mod use const char **var, *nqcvars[] = {"gamecfg", "scratch1", "scratch2", "scratch3", "scratch4", "saved1", "saved2", "saved3", "saved4", "savedgamecfg", "temp1", NULL}; for (var = nqcvars; *var; var++) Cvar_Create((char *)/*stupid const warning*/ *var, "0", 0); } // run the frame start qc function to let progs check cvars if (!pr_nqprogs) SV_ProgStartFrame (); // ********* External Entity support (.ent file(s) in gamedir/maps) pinched from ZQuake ********* // load and spawn all other entities entitystring = NULL; if ((int)sv_loadentfiles.value) { char ent_path[1024] = {0}; if (!entityfile || !entityfile[0]) entityfile = sv.mapname; // first try maps/sv_loadentfiles_dir/ if (sv_loadentfiles_dir.string[0]) { snprintf(ent_path, sizeof(ent_path), "maps/%s/%s.ent", sv_loadentfiles_dir.string, entityfile); entitystring = (char *) FS_LoadHunkFile(ent_path, NULL); } // try maps/ if not loaded yet. if (!entitystring) { snprintf(ent_path, sizeof(ent_path), "maps/%s.ent", entityfile); entitystring = (char *) FS_LoadHunkFile(ent_path, NULL); } if (entitystring) { Con_DPrintf ("Using entfile %s\n", ent_path); } } if (!entitystring) { entitystring = CM_EntityString(); } PR_LoadEnts(entitystring); // ********* End of External Entity support code ********* // look up some model indexes for specialized message compression SV_FindModelNumbers (); // all spawning is completed, any further precache statements // or prog writes to the signon message are errors sv.state = ss_active; // run two frames to allow everything to settle SV_Physics (); sv.time += 0.1; SV_Physics (); sv.time += 0.1; sv.old_time = sv.time; // save movement vars SV_SetMoveVars(); // create a baseline for more efficient communications SV_CreateBaseline (); sv.signon_buffer_size[sv.num_signon_buffers-1] = sv.signon.cursize; Info_SetValueForKey (svs.info, "map", sv.mapname, MAX_SERVERINFO_STRING); // calltimeofday. { extern void PF_calltimeofday (void); pr_global_struct->time = sv.time; pr_global_struct->self = 0; PF_calltimeofday(); } Con_DPrintf ("Server spawned.\n"); // we change map - clear whole demo struct and sent initial state to all dest if any (for QTV only I thought) SV_MVD_Record(NULL, true); #ifndef SERVERONLY CL_ClearState (); #endif }