/** * @brief Search the index in the config strings relative to a given start * @param name The value of the config string to search the index for * @param start The relative start point for the search * @param max The max. searched entries in the config string before giving up * @param create if @c true the value will get written into the config strings (appended) * @return @c 0 if not found */ static unsigned int SV_FindIndex (const char *name, int start, int max, qboolean create) { int i; if (!name || !name[0]) return 0; for (i = 1; i < max && SV_GetConfigString(start + i)[0] != '\0'; i++) { const char *configString = SV_GetConfigString(start + i); if (Q_streq(configString, name)) return i; } if (!create) return 0; if (i == max) Com_Error(ERR_DROP, "*Index: overflow '%s' start: %i, max: %i", name, start, max); SV_SetConfigString(start + i, name); if (Com_ServerState() != ss_loading) { /* send the update to everyone */ struct dbuffer *msg = new_dbuffer(); NET_WriteByte(msg, svc_configstring); NET_WriteShort(msg, start + i); NET_WriteString(msg, name); SV_Multicast(~0, msg); } return i; }
/** * @sa CL_ParseConfigString */ static void SV_Configstring (int index, const char *fmt, ...) { char val[MAX_TOKEN_CHARS * MAX_TILESTRINGS]; va_list argptr; if (index < 0 || index >= MAX_CONFIGSTRINGS) Com_Error(ERR_DROP, "configstring: bad index %i", index); va_start(argptr, fmt); Q_vsnprintf(val, sizeof(val), fmt, argptr); va_end(argptr); SV_SetConfigString(index, val); if (Com_ServerState() != ss_loading) { /* send the update to everyone */ struct dbuffer *msg = new_dbuffer(); NET_WriteByte(msg, svc_configstring); NET_WriteShort(msg, index); NET_WriteString(msg, val); /* send to all clients */ SV_Multicast(~0, msg); } }
/** * @sa CL_ParseConfigString */ static void SV_Configstring (int index, const char *fmt, ...) { char val[MAX_TOKEN_CHARS * MAX_TILESTRINGS]; va_list argptr; if (!Com_CheckConfigStringIndex(index)) SV_error("configstring: bad index %i", index); va_start(argptr, fmt); Q_vsnprintf(val, sizeof(val), fmt, argptr); va_end(argptr); SV_SetConfigString(index, val); if (Com_ServerState() != ss_loading) { /* send the update to everyone */ dbuffer msg(4 + strlen(val)); NET_WriteByte(&msg, svc_configstring); NET_WriteShort(&msg, index); NET_WriteString(&msg, val); /* send to all clients */ SV_Multicast(~0, msg); } }
/** * @brief Change the server to a new map, taking all connected clients along with it. * @note the full syntax is: @code map [day|night] [+]<map> [<assembly>] @endcode * @sa SV_AssembleMap * @sa CM_LoadMap * @sa Com_SetServerState */ void SV_Map (qboolean day, const char *levelstring, const char *assembly) { int i; unsigned checksum = 0; char * map = SV_GetConfigString(CS_TILES); char * pos = SV_GetConfigString(CS_POSITIONS); mapInfo_t *randomMap = NULL; client_t *cl; /* any partially connected client will be restarted */ Com_SetServerState(ss_restart); /* the game is just starting */ SV_InitGame(); if (!svs.initialized) { Com_Printf("Could not spawn the server\n"); return; } assert(levelstring[0] != '\0'); Com_DPrintf(DEBUG_SERVER, "SpawnServer: %s\n", levelstring); /* save name for levels that don't set message */ SV_SetConfigString(CS_NAME, levelstring); SV_SetConfigString(CS_LIGHTMAP, day); Q_strncpyz(sv->name, levelstring, sizeof(sv->name)); /* set serverinfo variable */ sv_mapname = Cvar_FullSet("sv_mapname", sv->name, CVAR_SERVERINFO | CVAR_NOSET); /* notify the client in case of a listening server */ SCR_BeginLoadingPlaque(); if (assembly) Q_strncpyz(sv->assembly, assembly, sizeof(sv->assembly)); else sv->assembly[0] = '\0'; /* leave slots at start for clients only */ cl = NULL; while ((cl = SV_GetNextClient(cl)) != NULL) { /* needs to reconnect */ if (cl->state >= cs_spawning) SV_SetClientState(cl, cs_connected); } /* assemble and load the map */ if (levelstring[0] == '+') { randomMap = SV_AssembleMap(levelstring + 1, assembly, map, pos, 0); if (!randomMap) { Com_Printf("Could not load assembly for map '%s'\n", levelstring); return; } } else { SV_SetConfigString(CS_TILES, levelstring); SV_SetConfigString(CS_POSITIONS, assembly ? assembly : ""); } CM_LoadMap(map, day, pos, &sv->mapData, &sv->mapTiles); Com_Printf("checksum for the map '%s': %u\n", levelstring, sv->mapData.mapChecksum); SV_SetConfigString(CS_MAPCHECKSUM, sv->mapData.mapChecksum); checksum = Com_GetScriptChecksum(); Com_Printf("ufo script checksum %u\n", checksum); SV_SetConfigString(CS_UFOCHECKSUM, checksum); SV_SetConfigString(CS_OBJECTAMOUNT, csi.numODs); SV_SetConfigString(CS_VERSION, UFO_VERSION); SV_SetConfigString(CS_MAPTITLE, SV_GetMapTitle(randomMap, levelstring)); if (Q_strstart(SV_GetConfigString(CS_MAPTITLE), "b/")) { /* For base attack, CS_MAPTITLE contains too many chars */ SV_SetConfigString(CS_MAPTITLE, "Base attack"); SV_SetConfigString(CS_NAME, ".baseattack"); } /* clear random-map assembly data */ Mem_Free(randomMap); randomMap = NULL; /* clear physics interaction links */ SV_ClearWorld(); /* fix this! */ for (i = 1; i <= sv->mapData.numInline; i++) sv->models[i] = CM_InlineModel(&sv->mapTiles, va("*%i", i)); /* precache and static commands can be issued during map initialization */ Com_SetServerState(ss_loading); TH_MutexLock(svs.serverMutex); /* load and spawn all other entities */ svs.ge->SpawnEntities(sv->name, SV_GetConfigStringInteger(CS_LIGHTMAP), sv->mapData.mapEntityString); TH_MutexUnlock(svs.serverMutex); /* all precaches are complete */ Com_SetServerState(ss_game); Com_Printf("-------------------------------------\n"); Cbuf_CopyToDefer(); }